diff --git a/src/EFCore.Jet/Extensions/JetDbContextOptionsBuilderExtensions.cs b/src/EFCore.Jet/Extensions/JetDbContextOptionsBuilderExtensions.cs
index 3c83769..1fa85f5 100644
--- a/src/EFCore.Jet/Extensions/JetDbContextOptionsBuilderExtensions.cs
+++ b/src/EFCore.Jet/Extensions/JetDbContextOptionsBuilderExtensions.cs
@@ -18,12 +18,71 @@ namespace Microsoft.EntityFrameworkCore
///
public static class JetDbContextOptionsBuilderExtensions
{
+ #region Connection String
+
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to. The underlying data
+ /// access provider (ODBC or OLE DB) will be inferred from the style of this connection string.
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ [CanBeNull] Action jetOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder) UseJet((DbContextOptionsBuilder) optionsBuilder, connectionString, jetOptionsAction);
+
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to. The underlying data
+ /// access provider (ODBC or OLE DB) will be inferred from the style of this connection string.
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ [CanBeNull] Action jetOptionsAction = null)
+ {
+ Check.NotNull(optionsBuilder, nameof(optionsBuilder));
+ Check.NotEmpty(connectionString, nameof(connectionString));
+
+ return UseJetCore(optionsBuilder, connectionString, null, JetConnection.GetDataAccessProviderType(connectionString), jetOptionsAction);
+ }
+
///
/// Configures the context to connect to a Microsoft Jet database.
///
/// The builder being used to configure the context.
/// The connection string of the database to connect to.
- /// A `OdbcFactory` or `OleDbFactory` object to be used for all
+ /// An `OdbcFactory` or `OleDbFactory` object to be used for all
+ /// data access operations by the Jet connection.
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ [NotNull] DbProviderFactory dataAccessProviderFactory,
+ [CanBeNull] Action jetOptionsAction = null)
+ where TContext : DbContext
+ {
+ Check.NotNull(optionsBuilder, nameof(optionsBuilder));
+ Check.NotEmpty(connectionString, nameof(connectionString));
+ Check.NotNull(dataAccessProviderFactory, nameof(dataAccessProviderFactory));
+
+ return (DbContextOptionsBuilder) UseJet((DbContextOptionsBuilder) optionsBuilder, connectionString, dataAccessProviderFactory, jetOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// An `OdbcFactory` or `OleDbFactory` object to be used for all
/// data access operations by the Jet connection.
/// An optional action to allow additional Jet specific configuration.
/// The options builder so that further configuration can be chained.
@@ -37,22 +96,78 @@ namespace Microsoft.EntityFrameworkCore
Check.NotEmpty(connectionString, nameof(connectionString));
Check.NotNull(dataAccessProviderFactory, nameof(dataAccessProviderFactory));
- return UseJetCore(optionsBuilder, connectionString, dataAccessProviderFactory, jetOptionsAction);
+ return UseJetCore(optionsBuilder, connectionString, dataAccessProviderFactory, null, jetOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// The type of the data access provider (`Odbc` or `OleDb`) to be used for all
+ /// data access operations by the Jet connection.
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ DataAccessProviderType dataAccessProviderType,
+ [CanBeNull] Action jetOptionsAction = null)
+ where TContext : DbContext
+ {
+ Check.NotNull(optionsBuilder, nameof(optionsBuilder));
+ Check.NotEmpty(connectionString, nameof(connectionString));
+
+ return (DbContextOptionsBuilder) UseJet((DbContextOptionsBuilder)optionsBuilder, connectionString, dataAccessProviderType, jetOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// The type of the data access provider (`Odbc` or `OleDb`) to be used for all
+ /// data access operations by the Jet connection.
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ DataAccessProviderType dataAccessProviderType,
+ [CanBeNull] Action jetOptionsAction = null)
+ {
+ Check.NotNull(optionsBuilder, nameof(optionsBuilder));
+ Check.NotEmpty(connectionString, nameof(connectionString));
+
+ return UseJetCore(optionsBuilder, connectionString, null, dataAccessProviderType, jetOptionsAction);
}
+ internal static DbContextOptionsBuilder UseJetWithoutPredefinedDataAccessProvider(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] string connectionString,
+ [CanBeNull] Action jetOptionsAction = null)
+ => UseJetCore(optionsBuilder, connectionString, null, null, jetOptionsAction);
+
private static DbContextOptionsBuilder UseJetCore(
[NotNull] DbContextOptionsBuilder optionsBuilder,
[NotNull] string connectionString,
[CanBeNull] DbProviderFactory dataAccessProviderFactory,
+ [CanBeNull] DataAccessProviderType? dataAccessProviderType,
Action jetOptionsAction)
{
Check.NotNull(optionsBuilder, nameof(optionsBuilder));
Check.NotEmpty(connectionString, nameof(connectionString));
+ if (dataAccessProviderFactory == null && dataAccessProviderType == null)
+ {
+ throw new ArgumentException($"One of the parameters {nameof(dataAccessProviderFactory)} and {nameof(dataAccessProviderType)} must not be null.");
+ }
+
var extension = (JetOptionsExtension) GetOrCreateExtension(optionsBuilder)
.WithConnectionString(connectionString);
- extension = extension.WithDataAccessProviderFactory(dataAccessProviderFactory);
+ extension = extension.WithDataAccessProviderFactory(
+ dataAccessProviderFactory ?? JetFactory.Instance.GetDataAccessProviderFactory(dataAccessProviderType.Value));
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(extension);
@@ -63,6 +178,31 @@ namespace Microsoft.EntityFrameworkCore
return optionsBuilder;
}
+ #endregion
+
+ #region Connection
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Microsoft Jet database.
+ ///
+ /// The type of context to be configured.
+ /// The builder being used to configure the context.
+ ///
+ /// An existing to be used to connect to the database. If the connection is
+ /// in the open state then EF will not open or close the connection. If the connection is in the closed
+ /// state then EF will open and close the connection as needed.
+ ///
+ /// An optional action to allow additional Jet specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseJet(
+ [NotNull] this DbContextOptionsBuilder optionsBuilder,
+ [NotNull] DbConnection connection,
+ [CanBeNull] Action jetOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder) UseJet(
+ (DbContextOptionsBuilder) optionsBuilder, connection, jetOptionsAction);
+
// Note: Decision made to use DbConnection not SqlConnection: Issue #772
///
/// Configures the context to connect to a Microsoft Jet database.
@@ -91,14 +231,16 @@ namespace Microsoft.EntityFrameworkCore
if (jetConnection.DataAccessProviderFactory == null)
{
- throw new ArgumentException($"The {nameof(connection)} parameter of type {nameof(JetConnection)} must have its {nameof(JetConnection.DataAccessProviderFactory)} property set to OdbcFactory or OleDbFactory.");
+ var dataAccessProviderType = JetConnection.GetDataAccessProviderType(jetConnection.ConnectionString);
+ jetConnection.DataAccessProviderFactory = JetFactory.Instance.GetDataAccessProviderFactory(dataAccessProviderType);
+ jetConnection.Freeze();
}
var extension = (JetOptionsExtension) GetOrCreateExtension(optionsBuilder)
.WithConnection(connection);
-
+
extension = extension.WithDataAccessProviderFactory(jetConnection.DataAccessProviderFactory);
-
+
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(extension);
ConfigureWarnings(optionsBuilder);
@@ -108,63 +250,8 @@ namespace Microsoft.EntityFrameworkCore
return optionsBuilder;
}
+ #endregion
- ///
- /// Configures the context to connect to a Microsoft Jet database.
- ///
- /// The builder being used to configure the context.
- /// The connection string of the database to connect to.
- /// A `OdbcFactory` or `OleDbFactory` object to be used for all
- /// data access operations by the Jet connection.
- /// An optional action to allow additional Jet specific configuration.
- /// The options builder so that further configuration can be chained.
- internal static DbContextOptionsBuilder UseJetWithoutPredefinedDataAccessProviderFactory(
- [NotNull] this DbContextOptionsBuilder optionsBuilder,
- [NotNull] string connectionString,
- [CanBeNull] Action jetOptionsAction = null)
- where TContext : DbContext
- => UseJetCore(optionsBuilder, connectionString, null, jetOptionsAction);
-
- ///
- /// Configures the context to connect to a Microsoft Jet database.
- ///
- /// The type of context to be configured.
- /// The builder being used to configure the context.
- /// The connection string of the database to connect to.
- /// A `OdbcFactory` or `OleDbFactory` object to be used for all
- /// data access operations by the Jet connection.
- /// An optional action to allow additional Jet specific configuration.
- /// The options builder so that further configuration can be chained.
- public static DbContextOptionsBuilder UseJet(
- [NotNull] this DbContextOptionsBuilder optionsBuilder,
- [NotNull] string connectionString,
- [NotNull] DbProviderFactory dataAccessProviderFactory,
- [CanBeNull] Action jetOptionsAction = null)
- where TContext : DbContext
- => (DbContextOptionsBuilder) UseJet(
- (DbContextOptionsBuilder) optionsBuilder, connectionString, dataAccessProviderFactory, jetOptionsAction);
-
- // Note: Decision made to use DbConnection not SqlConnection: Issue #772
- ///
- /// Configures the context to connect to a Microsoft Jet database.
- ///
- /// The type of context to be configured.
- /// The builder being used to configure the context.
- ///
- /// An existing to be used to connect to the database. If the connection is
- /// in the open state then EF will not open or close the connection. If the connection is in the closed
- /// state then EF will open and close the connection as needed.
- ///
- /// An optional action to allow additional Jet specific configuration.
- /// The options builder so that further configuration can be chained.
- public static DbContextOptionsBuilder UseJet(
- [NotNull] this DbContextOptionsBuilder optionsBuilder,
- [NotNull] DbConnection connection,
- [CanBeNull] Action jetOptionsAction = null)
- where TContext : DbContext
- => (DbContextOptionsBuilder) UseJet(
- (DbContextOptionsBuilder) optionsBuilder, connection, jetOptionsAction);
-
private static JetOptionsExtension GetOrCreateExtension(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.Options.FindExtension()
?? new JetOptionsExtension();
diff --git a/src/EFCore.Jet/Metadata/Conventions/JetConventionSetBuilder.cs b/src/EFCore.Jet/Metadata/Conventions/JetConventionSetBuilder.cs
index 0b048bb..260be5b 100644
--- a/src/EFCore.Jet/Metadata/Conventions/JetConventionSetBuilder.cs
+++ b/src/EFCore.Jet/Metadata/Conventions/JetConventionSetBuilder.cs
@@ -56,7 +56,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkJet()
.AddDbContext((p, o) => o
- .UseJetWithoutPredefinedDataAccessProviderFactory(
+ .UseJetWithoutPredefinedDataAccessProvider(
JetConnection.GetConnectionString("Jet.accdb", DataAccessProviderType.Odbc))
.UseInternalServiceProvider(p))
.BuildServiceProvider();
diff --git a/src/System.Data.Jet/JetConnection.cs b/src/System.Data.Jet/JetConnection.cs
index 1decee8..7f61f85 100644
--- a/src/System.Data.Jet/JetConnection.cs
+++ b/src/System.Data.Jet/JetConnection.cs
@@ -10,6 +10,7 @@ namespace System.Data.Jet
{
private ConnectionState _state;
private string _connectionString;
+ private bool _frozen;
internal DbConnection InnerConnection { get; private set; }
@@ -175,6 +176,10 @@ namespace System.Data.Jet
{
if (State != ConnectionState.Closed)
throw new InvalidOperationException(Messages.CannotChangePropertyValueInThisConnectionState(nameof(ConnectionString), State));
+
+ if (_frozen)
+ throw new InvalidOperationException($"Cannot modify \"{nameof(ConnectionString)}\" property after the connection has been frozen.");
+
_connectionString = value;
}
}
@@ -298,11 +303,15 @@ namespace System.Data.Jet
return;
if (string.IsNullOrWhiteSpace(_connectionString))
throw new InvalidOperationException(Messages.PropertyNotInitialized(nameof(ConnectionString)));
- if (JetFactory == null)
- throw new InvalidOperationException(Messages.PropertyNotInitialized(nameof(DataAccessProviderFactory)));
if (State != ConnectionState.Closed)
throw new InvalidOperationException(Messages.CannotCallMethodInThisConnectionState(nameof(Open), ConnectionState.Closed, State));
+ if (JetFactory == null)
+ {
+ var dataAccessProviderType = GetDataAccessProviderType(ConnectionString);
+ DataAccessProviderFactory = JetFactory.Instance.GetDataAccessProviderFactory(dataAccessProviderType);
+ }
+
try
{
InnerConnection = InnerConnectionFactory.Instance.OpenConnection(
@@ -404,6 +413,12 @@ namespace System.Data.Jet
return clone;
}
+ public void Freeze()
+ {
+ if (!string.IsNullOrWhiteSpace(ConnectionString))
+ _frozen = true;
+ }
+
///
/// Clears the pool.
///