diff --git a/src/EFCore.Jet.Data/DbConnectionStringBuilderExtensions.cs b/src/EFCore.Jet.Data/DbConnectionStringBuilderExtensions.cs index c648753..bca4e88 100644 --- a/src/EFCore.Jet.Data/DbConnectionStringBuilderExtensions.cs +++ b/src/EFCore.Jet.Data/DbConnectionStringBuilderExtensions.cs @@ -21,14 +21,14 @@ namespace EntityFrameworkCore.Jet.Data IsOdbc(builder)) { return builder.TryGetValue("DRIVER", out var value) - ? (string)value + ? ((string)value).TrimStart('{').TrimEnd('}') : null; } return builder.TryGetValue("Provider", out var oleDbValue) ? (string)oleDbValue : builder.TryGetValue("DRIVER", out var odbcValue) - ? (string)odbcValue + ? ((string)odbcValue).TrimStart('{').TrimEnd('}') : null; } diff --git a/src/EFCore.Jet.Data/JetConnectionStringBuilder.cs b/src/EFCore.Jet.Data/JetConnectionStringBuilder.cs new file mode 100644 index 0000000..81b43d1 --- /dev/null +++ b/src/EFCore.Jet.Data/JetConnectionStringBuilder.cs @@ -0,0 +1,88 @@ +using System; +using System.Data.Common; + +namespace EntityFrameworkCore.Jet.Data +{ + public class JetConnectionStringBuilder : DbConnectionStringBuilder + { + private readonly DbConnectionStringBuilder _innerBuilder; + + public JetConnectionStringBuilder() : this(JetConfiguration.DefaultDataAccessProviderType) + { + } + + public JetConnectionStringBuilder(DataAccessProviderType providerType) + { + ProviderType = providerType; + _innerBuilder = this; + } + + internal JetConnectionStringBuilder(DbProviderFactory innerFactory) + { + ProviderType = JetConnection.GetDataAccessProviderType(innerFactory); + _innerBuilder = innerFactory.CreateConnectionStringBuilder() ?? throw new InvalidOperationException($"CreateConnectionStringBuilder() returned null for {innerFactory}"); + } + + public DataAccessProviderType ProviderType { get; } + + public string? Provider + { + get => _innerBuilder.GetProvider(ProviderType); + set + { + _innerBuilder.SetProvider(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + + public string? DataSource + { + get => _innerBuilder.GetDataSource(ProviderType); + set + { + _innerBuilder.SetDataSource(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + + public string? UserId + { + get => _innerBuilder.GetUserId(ProviderType); + set + { + _innerBuilder.SetUserId(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + + public string? Password + { + get => _innerBuilder.GetPassword(ProviderType); + set + { + _innerBuilder.SetPassword(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + + public string? SystemDatabase + { + get => _innerBuilder.GetSystemDatabase(ProviderType); + set + { + _innerBuilder.SetSystemDatabase(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + + public string? DatabasePassword + { + get => _innerBuilder.GetDatabasePassword(ProviderType); + set + { + _innerBuilder.SetDatabasePassword(value!, ProviderType); + ConnectionString = _innerBuilder.ConnectionString; + } + } + } +} \ No newline at end of file diff --git a/src/EFCore.Jet.Data/JetFactory.cs b/src/EFCore.Jet.Data/JetFactory.cs index 333b0d5..dab43f9 100644 --- a/src/EFCore.Jet.Data/JetFactory.cs +++ b/src/EFCore.Jet.Data/JetFactory.cs @@ -82,7 +82,7 @@ namespace EntityFrameworkCore.Jet.Data public override DbConnectionStringBuilder CreateConnectionStringBuilder() => InnerFactory == null ? throw new InvalidOperationException(Messages.CannotCallJetProviderFactoryMethodOnSingletonInstance(nameof(CreateConnectionStringBuilder))) - : InnerFactory.CreateConnectionStringBuilder(); + : new JetConnectionStringBuilder(InnerFactory); /// /// Returns a new instance of the provider's class that implements the class. diff --git a/test/EFCore.Jet.Data.Tests/ConnectionStringTest.cs b/test/EFCore.Jet.Data.Tests/ConnectionStringTest.cs index 6bc0e7f..27e5dc7 100644 --- a/test/EFCore.Jet.Data.Tests/ConnectionStringTest.cs +++ b/test/EFCore.Jet.Data.Tests/ConnectionStringTest.cs @@ -1,4 +1,5 @@ using System.Data.Odbc; +using System.Data.OleDb; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EntityFrameworkCore.Jet.Data.Tests @@ -6,42 +7,128 @@ namespace EntityFrameworkCore.Jet.Data.Tests [TestClass] public class ConnectionStringTest { - [TestMethod] - public void Escape_double_quoted_connection_string() + [DataTestMethod] + [DataRow(DataAccessProviderType.Odbc)] + [DataRow(DataAccessProviderType.OleDb)] + public void Escape_double_quoted_connection_string(DataAccessProviderType providerType) { var expectedDatabaseName = "Joe's \"Recipes\" Database.accdb"; var escapedDatabaseName = expectedDatabaseName.Replace("\"", "\"\""); - - var connectionString = Helpers.DataAccessProviderFactory is OdbcFactory + + var connectionString = providerType == DataAccessProviderType.Odbc ? $"DBQ=\"{escapedDatabaseName}\"" : $"Data Source=\"{escapedDatabaseName}\""; - var csb = Helpers.DataAccessProviderFactory.CreateConnectionStringBuilder(); - csb.ConnectionString = connectionString; - - var actualDatabaseName = csb.GetDataSource(); - - Assert.AreEqual(expectedDatabaseName, actualDatabaseName); + var csb = new JetConnectionStringBuilder(providerType) { ConnectionString = connectionString }; + + Assert.AreEqual(expectedDatabaseName, csb.DataSource); } - - [TestMethod] - public void Escape_single_quoted_connection_string() + + [DataTestMethod] + [DataRow(DataAccessProviderType.Odbc)] + [DataRow(DataAccessProviderType.OleDb)] + public void Escape_single_quoted_connection_string(DataAccessProviderType providerType) { var expectedDatabaseName = "Joe's \"Recipes\" Database.accdb"; var escapedDatabaseName = expectedDatabaseName.Replace("'", "''"); - - var connectionString = Helpers.DataAccessProviderFactory is OdbcFactory + + var connectionString = providerType == DataAccessProviderType.Odbc ? $"DBQ='{escapedDatabaseName}'" : $"Data Source='{escapedDatabaseName}'"; - using var connection = new JetConnection(connectionString, Helpers.DataAccessProviderFactory); - - var csb = Helpers.DataAccessProviderFactory.CreateConnectionStringBuilder(); - csb.ConnectionString = connectionString; - - var actualDatabaseName = csb.GetDataSource(); - - Assert.AreEqual(expectedDatabaseName, actualDatabaseName); + var csb = new JetConnectionStringBuilder(providerType) { ConnectionString = connectionString }; + + Assert.AreEqual(expectedDatabaseName, csb.DataSource); + } + + [TestMethod] + public void Odbc_read_connection_string_with_all_properties() + { + const string connectionString = @"driver={Microsoft Access Driver (*.mdb, *.accdb)};dbq=C:\myFolder\myAccessFile.accdb;uid=Admin;pwd=hunter2;systemdb=SysDb"; + var csb = new JetConnectionStringBuilder(DataAccessProviderType.Odbc) { ConnectionString = connectionString }; + + Assert.AreEqual(csb.Provider, @"Microsoft Access Driver (*.mdb, *.accdb)"); + Assert.AreEqual(csb.DataSource, @"C:\myFolder\myAccessFile.accdb"); + Assert.AreEqual(csb.UserId, "Admin"); + Assert.AreEqual(csb.Password, "hunter2"); + Assert.AreEqual(csb.SystemDatabase, "SysDb"); + Assert.IsNull(csb.DatabasePassword); + } + + [TestMethod] + public void Odbc_connection_string_with_all_properties() + { + var csb = new JetConnectionStringBuilder(DataAccessProviderType.Odbc) + { + Provider = "Microsoft Access Driver (*.mdb, *.accdb)", + DataSource = @"C:\myFolder\myAccessFile.accdb", + UserId = "Admin", + Password = "hunter2", + SystemDatabase = "SysDb", + DatabasePassword = "DbPwd", + }; + + Assert.AreEqual(@"driver=""{Microsoft Access Driver (*.mdb, *.accdb)}"";dbq=C:\myFolder\myAccessFile.accdb;uid=Admin;pwd=DbPwd;systemdb=SysDb", csb.ConnectionString); + } + + [TestMethod] + public void Odbc_connection_string_with_all_properties_from_factory() + { + var csb = new JetConnection(OdbcFactory.Instance).JetFactory.CreateConnectionStringBuilder() as JetConnectionStringBuilder; + Assert.IsNotNull(csb); + csb.Provider = "Microsoft Access Driver (*.mdb, *.accdb)"; + csb.DataSource = @"C:\myFolder\myAccessFile.accdb"; + csb.UserId = "Admin"; + csb.Password = "hunter2"; + csb.SystemDatabase = "SysDb"; + csb.DatabasePassword = "DbPwd"; + + Assert.AreEqual(@"driver=""{Microsoft Access Driver (*.mdb, *.accdb)}"";dbq=C:\myFolder\myAccessFile.accdb;uid=Admin;pwd=DbPwd;systemdb=SysDb", csb.ConnectionString); + } + + [TestMethod] + public void OleDb_read_connection_string_with_all_properties() + { + const string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.accdb;User ID=Admin;Password=hunter2;Jet OLEDB:System Database=SysDb;Jet OLEDB:Database Password=DbPwd"; + var csb = new JetConnectionStringBuilder(DataAccessProviderType.OleDb) { ConnectionString = connectionString }; + + Assert.AreEqual(csb.Provider, "Microsoft.ACE.OLEDB.12.0"); + Assert.AreEqual(csb.DataSource, @"C:\myFolder\myAccessFile.accdb"); + Assert.AreEqual(csb.UserId, "Admin"); + Assert.AreEqual(csb.Password, "hunter2"); + Assert.AreEqual(csb.SystemDatabase, "SysDb"); + Assert.AreEqual(csb.DatabasePassword, "DbPwd"); + } + + [TestMethod] + public void OleDb_connection_string_with_all_properties() + { + var csb = new JetConnectionStringBuilder(DataAccessProviderType.OleDb) + { + Provider = "Microsoft.ACE.OLEDB.12.0", + DataSource = @"C:\myFolder\myAccessFile.accdb", + UserId = "Admin", + Password = "hunter2", + SystemDatabase = "SysDb", + DatabasePassword = "DbPwd", + }; + + Assert.AreEqual(@"provider=Microsoft.ACE.OLEDB.12.0;data source=C:\myFolder\myAccessFile.accdb;user id=Admin;password=hunter2;jet oledb:system database=SysDb;jet oledb:database password=DbPwd", csb.ConnectionString); + } + + [TestMethod] + public void OleDb_connection_string_with_all_properties_from_factory() + { + var csb = new JetConnection(OleDbFactory.Instance).JetFactory.CreateConnectionStringBuilder() as JetConnectionStringBuilder; + Assert.IsNotNull(csb); + csb.Provider = "Microsoft.ACE.OLEDB.12.0"; + csb.DataSource = @"C:\myFolder\myAccessFile.accdb"; + csb.UserId = "Admin"; + csb.Password = "hunter2"; + csb.SystemDatabase = "SysDb"; + csb.DatabasePassword = "DbPwd"; + + Assert.AreEqual(@"provider=Microsoft.ACE.OLEDB.12.0;data source=C:\myFolder\myAccessFile.accdb;password=hunter2;user id=Admin;jet oledb:system database=SysDb;jet oledb:database password=DbPwd", csb.ConnectionString); } } } \ No newline at end of file