diff --git a/src/EFCore.SqlServer/Extensions/SqlServerDbContextOptionsBuilderExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerDbContextOptionsBuilderExtensions.cs
index 7214fd81382..5e5ecf8127d 100644
--- a/src/EFCore.SqlServer/Extensions/SqlServerDbContextOptionsBuilderExtensions.cs
+++ b/src/EFCore.SqlServer/Extensions/SqlServerDbContextOptionsBuilderExtensions.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
+using Microsoft.EntityFrameworkCore.SqlServer.Internal;
// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore;
@@ -11,13 +12,13 @@ namespace Microsoft.EntityFrameworkCore;
///
///
/// See Using DbContextOptions, and
-/// Accessing SQL Server and Azure SQL databases with EF Core
+/// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
public static class SqlServerDbContextOptionsExtensions
{
///
- /// Configures the context to connect to a Microsoft SQL Server database, but without initially setting any
+ /// Configures the context to connect to a SQL Server database, but without initially setting any
/// or connection string.
///
///
@@ -28,52 +29,56 @@ public static class SqlServerDbContextOptionsExtensions
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
///
/// The builder being used to configure the context.
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
Action? sqlServerOptionsAction = null)
{
- ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(GetOrCreateExtension(optionsBuilder));
-
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = extension
+ .WithEngineType(SqlServerEngineType.SqlServer);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
}
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The builder being used to configure the context.
/// The connection string of the database to connect to.
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
string? connectionString,
Action? sqlServerOptionsAction = null)
{
- var extension = (SqlServerOptionsExtension)GetOrCreateExtension(optionsBuilder).WithConnectionString(connectionString);
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.SqlServer)
+ .WithConnectionString(connectionString);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
-
return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
}
// Note: Decision made to use DbConnection not SqlConnection: Issue #772
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The builder being used to configure the context.
@@ -83,7 +88,7 @@ public static DbContextOptionsBuilder UseSqlServer(
/// state then EF will open and close the connection as needed. The caller owns the connection and is
/// responsible for its disposal.
///
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -93,11 +98,11 @@ public static DbContextOptionsBuilder UseSqlServer(
// Note: Decision made to use DbConnection not SqlConnection: Issue #772
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The builder being used to configure the context.
@@ -111,7 +116,7 @@ public static DbContextOptionsBuilder UseSqlServer(
/// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
/// owns the connection and is responsible for its disposal.
///
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -121,14 +126,16 @@ public static DbContextOptionsBuilder UseSqlServer(
{
Check.NotNull(connection, nameof(connection));
- var extension = (SqlServerOptionsExtension)GetOrCreateExtension(optionsBuilder).WithConnection(connection, contextOwnsConnection);
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.SqlServer)
+ .WithConnection(connection, contextOwnsConnection);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
-
return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
}
///
- /// Configures the context to connect to a Microsoft SQL Server database, but without initially setting any
+ /// Configures the context to connect to a SQL Server database, but without initially setting any
/// or connection string.
///
///
@@ -139,12 +146,12 @@ public static DbContextOptionsBuilder UseSqlServer(
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
///
/// The builder being used to configure the context.
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -154,17 +161,17 @@ public static DbContextOptionsBuilder UseSqlServer(
(DbContextOptionsBuilder)optionsBuilder, sqlServerOptionsAction);
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The type of context to be configured.
/// The builder being used to configure the context.
/// The connection string of the database to connect to.
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -176,11 +183,11 @@ public static DbContextOptionsBuilder UseSqlServer(
// Note: Decision made to use DbConnection not SqlConnection: Issue #772
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The type of context to be configured.
@@ -191,7 +198,7 @@ public static DbContextOptionsBuilder UseSqlServer(
/// state then EF will open and close the connection as needed. The caller owns the connection and is
/// responsible for its disposal.
///
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -203,11 +210,11 @@ public static DbContextOptionsBuilder UseSqlServer(
// Note: Decision made to use DbConnection not SqlConnection: Issue #772
///
- /// Configures the context to connect to a Microsoft SQL Server database.
+ /// Configures the context to connect to a SQL Server database.
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
/// The type of context to be configured.
@@ -222,7 +229,7 @@ public static DbContextOptionsBuilder UseSqlServer(
/// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
/// owns the connection and is responsible for its disposal.
///
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// The options builder so that further configuration can be chained.
public static DbContextOptionsBuilder UseSqlServer(
this DbContextOptionsBuilder optionsBuilder,
@@ -233,9 +240,509 @@ public static DbContextOptionsBuilder UseSqlServer(
=> (DbContextOptionsBuilder)UseSqlServer(
(DbContextOptionsBuilder)optionsBuilder, connection, contextOwnsConnection, sqlServerOptionsAction);
- private static SqlServerOptionsExtension GetOrCreateExtension(DbContextOptionsBuilder optionsBuilder)
- => optionsBuilder.Options.FindExtension()
- ?? new SqlServerOptionsExtension();
+ ///
+ /// Configures the context to connect to a Azure SQL database, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ {
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = extension
+ .WithEngineType(SqlServerEngineType.AzureSql);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null)
+ {
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.AzureSql)
+ .WithConnectionString(connectionString);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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. The caller owns the connection and is
+ /// responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ Action? sqlServerOptionsAction = null)
+ => UseAzureSql(optionsBuilder, connection, false, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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.
+ ///
+ ///
+ /// If , then EF will take ownership of the connection and will
+ /// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
+ /// owns the connection and is responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ bool contextOwnsConnection,
+ Action? sqlServerOptionsAction = null)
+ {
+ Check.NotNull(connection, nameof(connection));
+
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.AzureSql)
+ .WithConnection(connection, contextOwnsConnection);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Azure SQL database, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSql(
+ (DbContextOptionsBuilder)optionsBuilder, sqlServerOptionsAction);
+
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// The type of context to be configured.
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSql(
+ (DbContextOptionsBuilder)optionsBuilder, connectionString, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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. The caller owns the connection and is
+ /// responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSql(
+ (DbContextOptionsBuilder)optionsBuilder, connection, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure SQL database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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.
+ ///
+ ///
+ /// If , then EF will take ownership of the connection and will
+ /// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
+ /// owns the connection and is responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSql(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ bool contextOwnsConnection,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSql(
+ (DbContextOptionsBuilder)optionsBuilder, connection, contextOwnsConnection, sqlServerOptionsAction);
+
+ ///
+ /// Configures the context to connect to a Azure Synapse database, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ {
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = extension
+ .WithEngineType(SqlServerEngineType.AzureSynapse);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null)
+ {
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.AzureSynapse)
+ .WithConnectionString(connectionString);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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. The caller owns the connection and is
+ /// responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ Action? sqlServerOptionsAction = null)
+ => UseAzureSynapse(optionsBuilder, connection, false, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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.
+ ///
+ ///
+ /// If , then EF will take ownership of the connection and will
+ /// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
+ /// owns the connection and is responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ bool contextOwnsConnection,
+ Action? sqlServerOptionsAction = null)
+ {
+ Check.NotNull(connection, nameof(connection));
+
+ var extension = GetOrCreateExtension(optionsBuilder);
+ extension = (SqlServerOptionsExtension)extension
+ .WithEngineType(SqlServerEngineType.AzureSynapse)
+ .WithConnection(connection, contextOwnsConnection);
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to a Azure Synapse database, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSynapse(
+ (DbContextOptionsBuilder)optionsBuilder, sqlServerOptionsAction);
+
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// The type of context to be configured.
+ /// The builder being used to configure the context.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSynapse(
+ (DbContextOptionsBuilder)optionsBuilder, connectionString, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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. The caller owns the connection and is
+ /// responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSynapse(
+ (DbContextOptionsBuilder)optionsBuilder, connection, sqlServerOptionsAction);
+
+ // Note: Decision made to use DbConnection not SqlConnection: Issue #772
+ ///
+ /// Configures the context to connect to a Azure Synapse database.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ /// 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.
+ ///
+ ///
+ /// If , then EF will take ownership of the connection and will
+ /// dispose it in the same way it would dispose a connection created by EF. If , then the caller still
+ /// owns the connection and is responsible for its disposal.
+ ///
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder UseAzureSynapse(
+ this DbContextOptionsBuilder optionsBuilder,
+ DbConnection connection,
+ bool contextOwnsConnection,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)UseAzureSynapse(
+ (DbContextOptionsBuilder)optionsBuilder, connection, contextOwnsConnection, sqlServerOptionsAction);
+
+ ///
+ /// Configures the context to connect to any of SQL Server, Azure SQL, Azure Synapse databases, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder ConfigureSqlEngine(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ {
+ ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(GetOrCreateExtension(optionsBuilder));
+ return ApplyConfiguration(optionsBuilder, sqlServerOptionsAction);
+ }
+
+ ///
+ /// Configures the context to connect to any of SQL Server, Azure SQL, Azure Synapse databases, but without initially setting any
+ /// or connection string.
+ ///
+ ///
+ ///
+ /// The connection or connection string must be set before the is used to connect
+ /// to a database. Set a connection using .
+ /// Set a connection string using .
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The builder being used to configure the context.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// The options builder so that further configuration can be chained.
+ public static DbContextOptionsBuilder ConfigureSqlEngine(
+ this DbContextOptionsBuilder optionsBuilder,
+ Action? sqlServerOptionsAction = null)
+ where TContext : DbContext
+ => (DbContextOptionsBuilder)ConfigureSqlEngine(
+ (DbContextOptionsBuilder)optionsBuilder, sqlServerOptionsAction);
+
+ private static T GetOrCreateExtension(DbContextOptionsBuilder optionsBuilder)
+ where T : RelationalOptionsExtension, new()
+ => optionsBuilder.Options.FindExtension()
+ ?? new T();
private static DbContextOptionsBuilder ApplyConfiguration(
DbContextOptionsBuilder optionsBuilder,
@@ -245,7 +752,7 @@ private static DbContextOptionsBuilder ApplyConfiguration(
sqlServerOptionsAction?.Invoke(new SqlServerDbContextOptionsBuilder(optionsBuilder));
- var extension = (SqlServerOptionsExtension)GetOrCreateExtension(optionsBuilder).ApplyDefaults(optionsBuilder.Options);
+ var extension = GetOrCreateExtension(optionsBuilder).ApplyDefaults(optionsBuilder.Options);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
return optionsBuilder;
diff --git a/src/EFCore.SqlServer/Extensions/SqlServerServiceCollectionExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerServiceCollectionExtensions.cs
index 12f2d4cf882..87f220451ed 100644
--- a/src/EFCore.SqlServer/Extensions/SqlServerServiceCollectionExtensions.cs
+++ b/src/EFCore.SqlServer/Extensions/SqlServerServiceCollectionExtensions.cs
@@ -15,7 +15,7 @@
namespace Microsoft.Extensions.DependencyInjection;
///
-/// SQL Server specific extension methods for .
+/// SQL Server, Azure SQL, Azure Synapse specific extension methods for .
///
public static class SqlServerServiceCollectionExtensions
{
@@ -45,14 +45,14 @@ public static class SqlServerServiceCollectionExtensions
///
///
/// See Using DbContextOptions, and
- /// Accessing SQL Server and Azure SQL databases with EF Core
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
/// for more information and examples.
///
///
/// The type of context to be registered.
/// The to add services to.
/// The connection string of the database to connect to.
- /// An optional action to allow additional SQL Server specific configuration.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
/// An optional action to configure the for the context.
/// The same service collection so that multiple calls can be chained.
public static IServiceCollection AddSqlServer(
@@ -91,6 +91,157 @@ public static IServiceCollection AddSqlServer(
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static IServiceCollection AddEntityFrameworkSqlServer(this IServiceCollection serviceCollection)
+ => AddEntityFrameworkSqlEngine(serviceCollection);
+
+ ///
+ /// Registers the given Entity Framework as a service in the
+ /// and configures it to connect to a Azure SQL database.
+ ///
+ ///
+ ///
+ /// This method is a shortcut for configuring a to use Azure SQL. It does not support all options.
+ /// Use and related methods for full control of
+ /// this process.
+ ///
+ ///
+ /// Use this method when using dependency injection in your application, such as with ASP.NET Core.
+ /// For applications that don't use dependency injection, consider creating
+ /// instances directly with its constructor. The method can then be
+ /// overridden to configure the Azure SQL provider and connection string.
+ ///
+ ///
+ /// To configure the for the context, either override the
+ /// method in your derived context, or supply
+ /// an optional action to configure the for the context.
+ ///
+ ///
+ /// See Using DbContext with dependency injection for more information and examples.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The type of context to be registered.
+ /// The to add services to.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// An optional action to configure the for the context.
+ /// The same service collection so that multiple calls can be chained.
+ public static IServiceCollection AddAzureSql(
+ this IServiceCollection serviceCollection,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null,
+ Action? optionsAction = null)
+ where TContext : DbContext
+ => serviceCollection.AddDbContext(
+ (_, options) =>
+ {
+ optionsAction?.Invoke(options);
+ options.UseAzureSql(connectionString, sqlServerOptionsAction);
+ });
+
+ ///
+ ///
+ /// Adds the services required by the Microsoft Azure SQL database provider for Entity Framework
+ /// to an .
+ ///
+ ///
+ /// Warning: Do not call this method accidentally. It is much more likely you need
+ /// to call .
+ ///
+ ///
+ ///
+ /// Calling this method is no longer necessary when building most applications, including those that
+ /// use dependency injection in ASP.NET or elsewhere.
+ /// It is only needed when building the internal service provider for use with
+ /// the method.
+ /// This is not recommend other than for some advanced scenarios.
+ ///
+ /// The to add services to.
+ ///
+ /// The same service collection so that multiple calls can be chained.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static IServiceCollection AddEntityFrameworkAzureSql(this IServiceCollection serviceCollection)
+ => AddEntityFrameworkSqlEngine(serviceCollection);
+
+ ///
+ /// Registers the given Entity Framework as a service in the
+ /// and configures it to connect to a Azure Synapse database.
+ ///
+ ///
+ ///
+ /// This method is a shortcut for configuring a to use Azure Synapse. It does not support all options.
+ /// Use and related methods for full control of
+ /// this process.
+ ///
+ ///
+ /// Use this method when using dependency injection in your application, such as with ASP.NET Core.
+ /// For applications that don't use dependency injection, consider creating
+ /// instances directly with its constructor. The method can then be
+ /// overridden to configure the Azure Synapse provider and connection string.
+ ///
+ ///
+ /// To configure the for the context, either override the
+ /// method in your derived context, or supply
+ /// an optional action to configure the for the context.
+ ///
+ ///
+ /// See Using DbContext with dependency injection for more information and examples.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ /// Accessing SQL Server, Azure SQL, Azure Synapse databases with EF Core
+ /// for more information and examples.
+ ///
+ ///
+ /// The type of context to be registered.
+ /// The to add services to.
+ /// The connection string of the database to connect to.
+ /// An optional action to allow additional SQL Server, Azure SQL, Azure Synapse specific configuration.
+ /// An optional action to configure the for the context.
+ /// The same service collection so that multiple calls can be chained.
+ public static IServiceCollection AddAzureSynapse(
+ this IServiceCollection serviceCollection,
+ string? connectionString,
+ Action? sqlServerOptionsAction = null,
+ Action? optionsAction = null)
+ where TContext : DbContext
+ => serviceCollection.AddDbContext(
+ (_, options) =>
+ {
+ optionsAction?.Invoke(options);
+ options.UseAzureSynapse(connectionString, sqlServerOptionsAction);
+ });
+
+ ///
+ ///
+ /// Adds the services required by the Microsoft Azure Synapse database provider for Entity Framework
+ /// to an .
+ ///
+ ///
+ /// Warning: Do not call this method accidentally. It is much more likely you need
+ /// to call .
+ ///
+ ///
+ ///
+ /// Calling this method is no longer necessary when building most applications, including those that
+ /// use dependency injection in ASP.NET or elsewhere.
+ /// It is only needed when building the internal service provider for use with
+ /// the method.
+ /// This is not recommend other than for some advanced scenarios.
+ ///
+ /// The to add services to.
+ ///
+ /// The same service collection so that multiple calls can be chained.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static IServiceCollection AddEntityFrameworkAzureSynapse(this IServiceCollection serviceCollection)
+ => AddEntityFrameworkSqlEngine(serviceCollection);
+
+ private static IServiceCollection AddEntityFrameworkSqlEngine(IServiceCollection serviceCollection)
{
new EntityFrameworkRelationalServicesBuilder(serviceCollection)
.TryAdd()
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
index f5f661d65d3..47728ddbc9d 100644
--- a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
@@ -17,7 +17,7 @@ public interface ISqlServerSingletonOptions : ISingletonOptions
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- int CompatibilityLevel { get; }
+ public SqlServerEngineType EngineType { get; }
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -25,5 +25,21 @@ public interface ISqlServerSingletonOptions : ISingletonOptions
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- int? CompatibilityLevelWithoutDefault { get; }
+ public int SqlServerCompatibilityLevel { get; }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public int AzureSqlCompatibilityLevel { get; }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public int AzureSynapseCompatibilityLevel { get; }
}
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerEngineType.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerEngineType.cs
new file mode 100644
index 00000000000..63f9c9816f4
--- /dev/null
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerEngineType.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
+
+///
+/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+/// the same compatibility standards as public APIs. It may be changed or removed without notice in
+/// any release. You should only use it directly in your code with extreme caution and knowing that
+/// doing so can result in application failures when updating to a new Entity Framework Core release.
+///
+public enum SqlServerEngineType
+{
+ ///
+ /// Unknown SQL engine type.
+ ///
+ Unknown = 0,
+
+ ///
+ /// SQL Server.
+ ///
+ SqlServer = 1,
+
+ ///
+ /// Azure SQL.
+ ///
+ AzureSql = 2,
+
+ ///
+ /// Azure Synapse.
+ ///
+ AzureSynapse = 3,
+}
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerOptionsExtension.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerOptionsExtension.cs
index ccf3d1961b9..2fb912637a7 100644
--- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerOptionsExtension.cs
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerOptionsExtension.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
+using Microsoft.EntityFrameworkCore.SqlServer.Internal;
namespace Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
@@ -14,8 +15,11 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
public class SqlServerOptionsExtension : RelationalOptionsExtension, IDbContextOptionsExtension
{
private DbContextOptionsExtensionInfo? _info;
- private int? _compatibilityLevel;
- private bool? _azureSql;
+ private SqlServerEngineType _engineType;
+ private bool _legacyAzureSql;
+ private int? _sqlServerCompatibilityLevel;
+ private int? _azureSqlCompatibilityLevel;
+ private int? _azureSynapseCompatibilityLevel;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -29,7 +33,30 @@ public class SqlServerOptionsExtension : RelationalOptionsExtension, IDbContextO
// SQL Server 2017 (14.x): compatibility level 140, start date 2017-09-29, mainstream end date 2022-10-11, extended end date 2027-10-12
// SQL Server 2016 (13.x): compatibility level 130, start date 2016-06-01, mainstream end date 2021-07-13, extended end date 2026-07-14
// SQL Server 2014 (12.x): compatibility level 120, start date 2014-06-05, mainstream end date 2019-07-09, extended end date 2024-07-09
- public static readonly int DefaultCompatibilityLevel = 150;
+ public static readonly int SqlServerDefaultCompatibilityLevel = 150;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ // See https://learn.microsoft.com/sql/t-sql/statements/alter-database-transact-sql-compatibility-level
+ // SQL Server 2022 (16.x): compatibility level 160, start date 2022-11-16, mainstream end date 2028-01-11, extended end date 2033-01-11
+ // SQL Server 2019 (15.x): compatibility level 150, start date 2019-11-04, mainstream end date 2025-02-28, extended end date 2030-01-08
+ // SQL Server 2017 (14.x): compatibility level 140, start date 2017-09-29, mainstream end date 2022-10-11, extended end date 2027-10-12
+ // SQL Server 2016 (13.x): compatibility level 130, start date 2016-06-01, mainstream end date 2021-07-13, extended end date 2026-07-14
+ // SQL Server 2014 (12.x): compatibility level 120, start date 2014-06-05, mainstream end date 2019-07-09, extended end date 2024-07-09
+ public static readonly int AzureSqlDefaultCompatibilityLevel = 150;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ // See https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-scoped-configuration-transact-sql
+ public static readonly int AzureSynapseDefaultCompatibilityLevel = 30;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -52,8 +79,11 @@ public SqlServerOptionsExtension()
protected SqlServerOptionsExtension(SqlServerOptionsExtension copyFrom)
: base(copyFrom)
{
- _compatibilityLevel = copyFrom._compatibilityLevel;
- _azureSql = copyFrom._azureSql;
+ _engineType = copyFrom._engineType;
+ _legacyAzureSql = copyFrom._legacyAzureSql;
+ _sqlServerCompatibilityLevel = copyFrom._sqlServerCompatibilityLevel;
+ _azureSqlCompatibilityLevel = copyFrom._azureSqlCompatibilityLevel;
+ _azureSynapseCompatibilityLevel = copyFrom._azureSynapseCompatibilityLevel;
}
///
@@ -80,8 +110,64 @@ protected override RelationalOptionsExtension Clone()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual int CompatibilityLevel
- => _compatibilityLevel ?? DefaultCompatibilityLevel;
+ public virtual SqlServerEngineType EngineType
+ => _engineType;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual bool LegacyAzureSql
+ => _legacyAzureSql;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int SqlServerCompatibilityLevel
+ => _sqlServerCompatibilityLevel ?? SqlServerDefaultCompatibilityLevel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int AzureSqlCompatibilityLevel
+ => _azureSqlCompatibilityLevel ?? AzureSqlDefaultCompatibilityLevel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int AzureSynapseCompatibilityLevel
+ => _azureSynapseCompatibilityLevel ?? AzureSynapseDefaultCompatibilityLevel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual SqlServerOptionsExtension WithEngineType(SqlServerEngineType engineType)
+ {
+ if (EngineType != SqlServerEngineType.Unknown && EngineType != engineType)
+ {
+ throw new InvalidOperationException(SqlServerStrings.AlreadyConfiguredEngineType(engineType, EngineType));
+ }
+
+ var clone = (SqlServerOptionsExtension)Clone();
+
+ clone._engineType = engineType;
+
+ return clone;
+ }
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -89,8 +175,15 @@ public virtual int CompatibilityLevel
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual int? CompatibilityLevelWithoutDefault
- => _compatibilityLevel;
+ public virtual SqlServerOptionsExtension WithLegacyAzureSql(bool enable)
+ {
+ var clone = (SqlServerOptionsExtension)Clone();
+
+ clone._engineType = SqlServerEngineType.SqlServer;
+ clone._legacyAzureSql = enable;
+
+ return clone;
+ }
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -98,11 +191,11 @@ public virtual int? CompatibilityLevelWithoutDefault
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual SqlServerOptionsExtension WithCompatibilityLevel(int? compatibilityLevel)
+ public virtual SqlServerOptionsExtension WithSqlServerCompatibilityLevel(int? sqlServerCompatibilityLevel)
{
var clone = (SqlServerOptionsExtension)Clone();
- clone._compatibilityLevel = compatibilityLevel;
+ clone._sqlServerCompatibilityLevel = sqlServerCompatibilityLevel;
return clone;
}
@@ -113,8 +206,14 @@ public virtual SqlServerOptionsExtension WithCompatibilityLevel(int? compatibili
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual bool IsAzureSql
- => _azureSql ?? false;
+ public virtual SqlServerOptionsExtension WithAzureSqlCompatibilityLevel(int? azureSqlCompatibilityLevel)
+ {
+ var clone = (SqlServerOptionsExtension)Clone();
+
+ clone._azureSqlCompatibilityLevel = azureSqlCompatibilityLevel;
+
+ return clone;
+ }
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -122,11 +221,11 @@ public virtual bool IsAzureSql
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual SqlServerOptionsExtension WithAzureSql(bool enable)
+ public virtual SqlServerOptionsExtension WithAzureSynapseCompatibilityLevel(int? azureSynapseCompatibilityLevel)
{
var clone = (SqlServerOptionsExtension)Clone();
- clone._azureSql = enable;
+ clone._azureSynapseCompatibilityLevel = _azureSynapseCompatibilityLevel;
return clone;
}
@@ -134,12 +233,8 @@ public virtual SqlServerOptionsExtension WithAzureSql(bool enable)
///
public virtual IDbContextOptionsExtension ApplyDefaults(IDbContextOptions options)
{
- if (!IsAzureSql)
- {
- return this;
- }
-
- if (ExecutionStrategyFactory == null)
+ if (ExecutionStrategyFactory == null
+ && (EngineType == SqlServerEngineType.AzureSql || EngineType == SqlServerEngineType.AzureSynapse || LegacyAzureSql))
{
return WithExecutionStrategyFactory(c => new SqlServerRetryingExecutionStrategy(c));
}
@@ -154,7 +249,35 @@ public virtual IDbContextOptionsExtension ApplyDefaults(IDbContextOptions option
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public override void ApplyServices(IServiceCollection services)
- => services.AddEntityFrameworkSqlServer();
+ {
+ switch (_engineType)
+ {
+ case SqlServerEngineType.SqlServer:
+ services.AddEntityFrameworkSqlServer();
+ break;
+ case SqlServerEngineType.AzureSql:
+ services.AddEntityFrameworkAzureSql();
+ break;
+ case SqlServerEngineType.AzureSynapse:
+ services.AddEntityFrameworkAzureSynapse();
+ break;
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public override void Validate(IDbContextOptions options)
+ {
+ base.Validate(options);
+ if (EngineType == SqlServerEngineType.Unknown)
+ {
+ throw new InvalidOperationException(SqlServerStrings.InvalidEngineType($"{nameof(SqlServerDbContextOptionsExtensions.UseSqlServer)}/{nameof(SqlServerDbContextOptionsExtensions.UseAzureSql)}/{nameof(SqlServerDbContextOptionsExtensions.UseAzureSynapse)}"));
+ }
+ }
private sealed class ExtensionInfo : RelationalExtensionInfo
{
@@ -168,12 +291,12 @@ public ExtensionInfo(IDbContextOptionsExtension extension)
private new SqlServerOptionsExtension Extension
=> (SqlServerOptionsExtension)base.Extension;
- public override bool IsDatabaseProvider
- => true;
-
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
=> other is ExtensionInfo otherInfo
- && Extension.CompatibilityLevel == otherInfo.Extension.CompatibilityLevel;
+ && Extension.EngineType == otherInfo.Extension.EngineType
+ && Extension.SqlServerCompatibilityLevel == otherInfo.Extension.SqlServerCompatibilityLevel
+ && Extension.AzureSqlCompatibilityLevel == otherInfo.Extension.AzureSqlCompatibilityLevel
+ && Extension.AzureSynapseCompatibilityLevel == otherInfo.Extension.AzureSynapseCompatibilityLevel;
public override string LogFragment
{
@@ -185,11 +308,39 @@ public override string LogFragment
builder.Append(base.LogFragment);
- if (Extension._compatibilityLevel is int compatibilityLevel)
+ builder
+ .Append("EngineType=")
+ .Append(Extension._engineType)
+ .Append(' ');
+
+ if (Extension._legacyAzureSql)
{
builder
- .Append("CompatibilityLevel=")
- .Append(compatibilityLevel);
+ .Append("LegacyAzureSql=")
+ .Append(Extension._legacyAzureSql)
+ .Append(' ');
+ }
+
+ if (Extension._sqlServerCompatibilityLevel != null)
+ {
+ builder
+ .Append("SqlServerCompatibilityLevel=")
+ .Append(Extension._sqlServerCompatibilityLevel)
+ .Append(' ');
+ }
+ if (Extension._azureSqlCompatibilityLevel != null)
+ {
+ builder
+ .Append("AzureSqlCompatibilityLevel=")
+ .Append(Extension._azureSqlCompatibilityLevel)
+ .Append(' ');
+ }
+ if (Extension._azureSynapseCompatibilityLevel != null)
+ {
+ builder
+ .Append("AzureSynapseCompatibilityLevel=")
+ .Append(Extension._azureSynapseCompatibilityLevel)
+ .Append(' ');
}
_logFragment = builder.ToString();
@@ -201,11 +352,20 @@ public override string LogFragment
public override void PopulateDebugInfo(IDictionary debugInfo)
{
- debugInfo["SqlServer"] = "1";
+ debugInfo["EngineType"] = Extension.EngineType.ToString();
+ debugInfo["LegacyAzureSql"] = Extension.LegacyAzureSql.ToString();
- if (Extension.CompatibilityLevel is int compatibilityLevel)
+ if (Extension.SqlServerCompatibilityLevel is int sqlServerCompatibilityLevel)
+ {
+ debugInfo["SqlServerCompatibilityLevel"] = sqlServerCompatibilityLevel.ToString();
+ }
+ if (Extension.AzureSqlCompatibilityLevel is int azureSqlCompatibilityLevel)
+ {
+ debugInfo["AzureSqlCompatibilityLevel"] = azureSqlCompatibilityLevel.ToString();
+ }
+ if (Extension.AzureSynapseCompatibilityLevel is int azureSynapseCompatibilityLevel)
{
- debugInfo["CompatibilityLevel"] = compatibilityLevel.ToString();
+ debugInfo["AzureSynapseCompatibilityLevel"] = azureSynapseCompatibilityLevel.ToString();
}
}
}
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
index cba62d8cd69..3af5096042c 100644
--- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
@@ -17,7 +17,7 @@ public class SqlServerSingletonOptions : ISqlServerSingletonOptions
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual int CompatibilityLevel { get; private set; } = SqlServerOptionsExtension.DefaultCompatibilityLevel;
+ public virtual SqlServerEngineType EngineType { get; private set; }
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -25,7 +25,23 @@ public class SqlServerSingletonOptions : ISqlServerSingletonOptions
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual int? CompatibilityLevelWithoutDefault { get; private set; }
+ public virtual int SqlServerCompatibilityLevel { get; private set; } = SqlServerOptionsExtension.SqlServerDefaultCompatibilityLevel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int AzureSqlCompatibilityLevel { get; private set; } = SqlServerOptionsExtension.AzureSqlDefaultCompatibilityLevel;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual int AzureSynapseCompatibilityLevel { get; private set; } = SqlServerOptionsExtension.AzureSynapseDefaultCompatibilityLevel;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -38,8 +54,10 @@ public virtual void Initialize(IDbContextOptions options)
var sqlServerOptions = options.FindExtension();
if (sqlServerOptions != null)
{
- CompatibilityLevel = sqlServerOptions.CompatibilityLevel;
- CompatibilityLevelWithoutDefault = sqlServerOptions.CompatibilityLevelWithoutDefault;
+ EngineType = sqlServerOptions.EngineType;
+ SqlServerCompatibilityLevel = sqlServerOptions.SqlServerCompatibilityLevel;
+ AzureSqlCompatibilityLevel = sqlServerOptions.AzureSqlCompatibilityLevel;
+ AzureSynapseCompatibilityLevel = sqlServerOptions.AzureSynapseCompatibilityLevel;
}
}
@@ -51,16 +69,34 @@ public virtual void Initialize(IDbContextOptions options)
///
public virtual void Validate(IDbContextOptions options)
{
- var sqlserverOptions = options.FindExtension();
+ var sqlServerOptions = options.FindExtension();
- if (sqlserverOptions != null
- && (CompatibilityLevelWithoutDefault != sqlserverOptions.CompatibilityLevelWithoutDefault
- || CompatibilityLevel != sqlserverOptions.CompatibilityLevel))
+ if (sqlServerOptions != null)
{
- throw new InvalidOperationException(
- CoreStrings.SingletonOptionChanged(
- nameof(SqlServerDbContextOptionsExtensions.UseSqlServer),
- nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
+ if (EngineType == SqlServerEngineType.SqlServer
+ && (EngineType != sqlServerOptions.EngineType || SqlServerCompatibilityLevel != sqlServerOptions.SqlServerCompatibilityLevel))
+ {
+ throw new InvalidOperationException(
+ CoreStrings.SingletonOptionChanged(
+ $"{nameof(SqlServerDbContextOptionsExtensions.UseSqlServer)}",
+ nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
+ }
+ if (EngineType == SqlServerEngineType.AzureSql
+ && (EngineType != sqlServerOptions.EngineType || AzureSqlCompatibilityLevel != sqlServerOptions.AzureSqlCompatibilityLevel))
+ {
+ throw new InvalidOperationException(
+ CoreStrings.SingletonOptionChanged(
+ $"{nameof(SqlServerDbContextOptionsExtensions.UseAzureSql)}",
+ nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
+ }
+ if (EngineType == SqlServerEngineType.AzureSynapse
+ && (EngineType != sqlServerOptions.EngineType || AzureSynapseCompatibilityLevel != sqlServerOptions.AzureSynapseCompatibilityLevel))
+ {
+ throw new InvalidOperationException(
+ CoreStrings.SingletonOptionChanged(
+ $"{nameof(SqlServerDbContextOptionsExtensions.UseAzureSynapse)}",
+ nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
+ }
}
}
}
diff --git a/src/EFCore.SqlServer/Infrastructure/SqlServerDbContextOptionsBuilder.cs b/src/EFCore.SqlServer/Infrastructure/SqlServerDbContextOptionsBuilder.cs
index c3f74d0bd91..863dcac7192 100644
--- a/src/EFCore.SqlServer/Infrastructure/SqlServerDbContextOptionsBuilder.cs
+++ b/src/EFCore.SqlServer/Infrastructure/SqlServerDbContextOptionsBuilder.cs
@@ -6,10 +6,13 @@
namespace Microsoft.EntityFrameworkCore.Infrastructure;
///
-/// Allows SQL Server specific configuration to be performed on .
+/// Allows SQL Server, Azure SQL, Azure Synapse specific configuration to be performed on .
///
///
-/// Instances of this class are returned from a call to
+/// Instances of this class are returned from a call to
+/// ,
+/// ,
+///
/// and it is not designed to be directly constructed in your application code.
///
public class SqlServerDbContextOptionsBuilder
@@ -29,7 +32,7 @@ public SqlServerDbContextOptionsBuilder(DbContextOptionsBuilder optionsBuilder)
///
///
///
- /// This strategy is specifically tailored to SQL Server (including Azure SQL). It is pre-configured with
+ /// This strategy is specifically tailored to SQL Server, Azure SQL, Azure Synapse. It is pre-configured with
/// error numbers for transient errors that can be retried.
///
///
@@ -48,7 +51,7 @@ public virtual SqlServerDbContextOptionsBuilder EnableRetryOnFailure()
///
///
///
- /// This strategy is specifically tailored to SQL Server (including Azure SQL). It is pre-configured with
+ /// This strategy is specifically tailored to SQL Server, Azure SQL, Azure Synapse. It is pre-configured with
/// error numbers for transient errors that can be retried.
///
///
@@ -67,7 +70,7 @@ public virtual SqlServerDbContextOptionsBuilder EnableRetryOnFailure(int maxRetr
///
///
///
- /// This strategy is specifically tailored to SQL Server (including Azure SQL). It is pre-configured with
+ /// This strategy is specifically tailored to SQL Server, Azure SQL, Azure Synapse. It is pre-configured with
/// error numbers for transient errors that can be retried.
///
///
@@ -87,7 +90,7 @@ public virtual SqlServerDbContextOptionsBuilder EnableRetryOnFailure(ICollection
///
///
///
- /// This strategy is specifically tailored to SQL Server (including Azure SQL). It is pre-configured with
+ /// This strategy is specifically tailored to SQL Server, Azure SQL, Azure Synapse. It is pre-configured with
/// error numbers for transient errors that can be retried, but additional error numbers can also be supplied.
///
///
@@ -116,14 +119,45 @@ public virtual SqlServerDbContextOptionsBuilder EnableRetryOnFailure(
///
/// for more information and examples.
///
- /// to have null resource
- public virtual SqlServerDbContextOptionsBuilder UseCompatibilityLevel(int compatibilityLevel)
- => WithOption(e => e.WithCompatibilityLevel(compatibilityLevel));
+ /// to have null resource
+ public virtual SqlServerDbContextOptionsBuilder UseSqlServerCompatibilityLevel(int sqlServerCompatibilityLevel)
+ => WithOption(e => e.WithSqlServerCompatibilityLevel(sqlServerCompatibilityLevel));
///
/// Configures the context to use defaults optimized for Azure SQL, including retries on errors.
///
/// Whether the defaults should be enabled.
+ [Obsolete("Use UseAzureSql instead of UseSqlServer with UseAzureSqlDefaults.")]
public virtual SqlServerDbContextOptionsBuilder UseAzureSqlDefaults(bool enable = true)
- => WithOption(e => e.WithAzureSql(enable));
+ => WithOption(e => e.WithLegacyAzureSql(enable));
+
+ ///
+ /// Sets the Azure SQL compatibility level that EF Core will use when interacting with the database. This allows configuring EF
+ /// Core to work with older (or newer) versions of Azure SQL. Defaults to 160.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ ///
+ /// Azure SQL documentation on compatibility level
+ ///
+ /// for more information and examples.
+ ///
+ /// to have null resource
+ public virtual SqlServerDbContextOptionsBuilder UseAzureSqlCompatibilityLevel(int azureSqlCompatibilityLevel)
+ => WithOption(e => e.WithAzureSqlCompatibilityLevel(azureSqlCompatibilityLevel));
+
+ ///
+ /// Sets the Azure Synapse compatibility level that EF Core will use when interacting with the database. This allows configuring EF
+ /// Core to work with older (or newer) versions of Azure Synapse. Defaults to 30.
+ ///
+ ///
+ /// See Using DbContextOptions, and
+ ///
+ /// Azure Synapse documentation on compatibility level
+ ///
+ /// for more information and examples.
+ ///
+ /// to have null resource
+ public virtual SqlServerDbContextOptionsBuilder UseAzureSynapseCompatibilityLevel(int azureSynapseCompatibilityLevel)
+ => WithOption(e => e.WithAzureSynapseCompatibilityLevel(azureSynapseCompatibilityLevel));
}
diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
index 44bf55728a3..a2394614e7c 100644
--- a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
+++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
@@ -23,6 +23,14 @@ public static class SqlServerStrings
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.EntityFrameworkCore.SqlServer.Properties.SqlServerStrings", typeof(SqlServerStrings).Assembly);
+ ///
+ /// Cannot configure engine type '{newEngineType}', because engine type was already configured as '{oldEngineType}'.
+ ///
+ public static string AlreadyConfiguredEngineType(object? newEngineType, object? oldEngineType)
+ => string.Format(
+ GetString("AlreadyConfiguredEngineType", nameof(newEngineType), nameof(oldEngineType)),
+ newEngineType, oldEngineType);
+
///
/// To change the IDENTITY property of a column, the column needs to be dropped and recreated.
///
@@ -207,6 +215,14 @@ public static string IndexTableRequired
public static string InvalidColumnNameForFreeText
=> GetString("InvalidColumnNameForFreeText");
+ ///
+ /// Engine type was not configured. Use one of {methods} to configure it.
+ ///
+ public static string InvalidEngineType(object? methods)
+ => string.Format(
+ GetString("InvalidEngineType", nameof(methods)),
+ methods);
+
///
/// The specified table '{table}' is not in a valid format. Specify tables using the format '[schema].[table]'.
///
diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
index ba817be851a..5b734aebd29 100644
--- a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
+++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Cannot configure engine type '{newEngineType}', because engine type was already configured as '{oldEngineType}'.
+
To change the IDENTITY property of a column, the column needs to be dropped and recreated.
@@ -189,6 +192,9 @@
The expression passed to the 'propertyReference' parameter of the 'FreeText' method is not a valid reference to a property. The expression must represent a reference to a full-text indexed property on the object referenced in the from clause: 'from e in context.Entities where EF.Functions.FreeText(e.SomeProperty, textToSearchFor) select e'
+
+ Engine type was not configured. Use one of {methods} to configure it.
+
The specified table '{table}' is not in a valid format. Specify tables using the format '[schema].[table]'.
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
index 994ee50a4f8..67c7726df4a 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
@@ -19,7 +19,7 @@ public class SqlServerQuerySqlGenerator : QuerySqlGenerator
{
private readonly IRelationalTypeMappingSource _typeMappingSource;
private readonly ISqlGenerationHelper _sqlGenerationHelper;
- private readonly int _sqlServerCompatibilityLevel;
+ private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions;
private bool _withinTable;
@@ -37,7 +37,7 @@ public SqlServerQuerySqlGenerator(
{
_typeMappingSource = typeMappingSource;
_sqlGenerationHelper = dependencies.SqlGenerationHelper;
- _sqlServerCompatibilityLevel = sqlServerSingletonOptions.CompatibilityLevel;
+ _sqlServerSingletonOptions = sqlServerSingletonOptions;
}
///
@@ -520,18 +520,26 @@ private void GenerateJsonPath(IReadOnlyList path)
{
Visit(arrayIndex);
}
- else if (_sqlServerCompatibilityLevel >= 140)
- {
- Sql.Append("' + CAST(");
- Visit(arrayIndex);
- Sql.Append(" AS ");
- Sql.Append(_typeMappingSource.GetMapping(typeof(string)).StoreType);
- Sql.Append(") + '");
- }
else
{
- throw new InvalidOperationException(
- SqlServerStrings.JsonValuePathExpressionsNotSupported(_sqlServerCompatibilityLevel));
+ switch (_sqlServerSingletonOptions.EngineType)
+ {
+ case SqlServerEngineType.SqlServer when _sqlServerSingletonOptions.SqlServerCompatibilityLevel >= 140:
+ case SqlServerEngineType.AzureSql when _sqlServerSingletonOptions.AzureSqlCompatibilityLevel >= 140:
+ case SqlServerEngineType.AzureSynapse:
+ Sql.Append("' + CAST(");
+ Visit(arrayIndex);
+ Sql.Append(" AS ");
+ Sql.Append(_typeMappingSource.GetMapping(typeof(string)).StoreType);
+ Sql.Append(") + '");
+ break;
+ case SqlServerEngineType.SqlServer:
+ throw new InvalidOperationException(
+ SqlServerStrings.JsonValuePathExpressionsNotSupported(_sqlServerSingletonOptions.SqlServerCompatibilityLevel));
+ case SqlServerEngineType.AzureSql:
+ throw new InvalidOperationException(
+ SqlServerStrings.JsonValuePathExpressionsNotSupported(_sqlServerSingletonOptions.AzureSqlCompatibilityLevel));
+ }
}
Sql.Append("]");
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
index 9ce6e9d5425..c48965fc33f 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
@@ -20,7 +20,7 @@ public class SqlServerQueryableMethodTranslatingExpressionVisitor : RelationalQu
private readonly SqlServerQueryCompilationContext _queryCompilationContext;
private readonly IRelationalTypeMappingSource _typeMappingSource;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
- private readonly int _sqlServerCompatibilityLevel;
+ private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions;
private RelationalTypeMapping? _nvarcharMaxTypeMapping;
@@ -40,8 +40,7 @@ public SqlServerQueryableMethodTranslatingExpressionVisitor(
_queryCompilationContext = queryCompilationContext;
_typeMappingSource = relationalDependencies.TypeMappingSource;
_sqlExpressionFactory = relationalDependencies.SqlExpressionFactory;
-
- _sqlServerCompatibilityLevel = sqlServerSingletonOptions.CompatibilityLevel;
+ _sqlServerSingletonOptions = sqlServerSingletonOptions;
}
///
@@ -57,8 +56,7 @@ protected SqlServerQueryableMethodTranslatingExpressionVisitor(
_queryCompilationContext = parentVisitor._queryCompilationContext;
_typeMappingSource = parentVisitor._typeMappingSource;
_sqlExpressionFactory = parentVisitor._sqlExpressionFactory;
-
- _sqlServerCompatibilityLevel = parentVisitor._sqlServerCompatibilityLevel;
+ _sqlServerSingletonOptions = parentVisitor._sqlServerSingletonOptions;
}
///
@@ -131,9 +129,15 @@ protected override Expression VisitExtension(Expression extensionExpression)
IProperty? property,
string tableAlias)
{
- if (_sqlServerCompatibilityLevel < 130)
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer && _sqlServerSingletonOptions.SqlServerCompatibilityLevel < 130)
+ {
+ AddTranslationErrorDetails(SqlServerStrings.CompatibilityLevelTooLowForScalarCollections(_sqlServerSingletonOptions.SqlServerCompatibilityLevel));
+
+ return null;
+ }
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel < 130)
{
- AddTranslationErrorDetails(SqlServerStrings.CompatibilityLevelTooLowForScalarCollections(_sqlServerCompatibilityLevel));
+ AddTranslationErrorDetails(SqlServerStrings.CompatibilityLevelTooLowForScalarCollections(_sqlServerSingletonOptions.AzureSqlCompatibilityLevel));
return null;
}
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlExpressionFactory.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlExpressionFactory.cs
index df768474719..f84f3e1abb8 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlExpressionFactory.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlExpressionFactory.cs
@@ -16,7 +16,6 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
public class SqlServerSqlExpressionFactory : SqlExpressionFactory
{
private readonly IRelationalTypeMappingSource _typeMappingSource;
- private readonly int _sqlServerCompatibilityLevel;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -25,12 +24,10 @@ public class SqlServerSqlExpressionFactory : SqlExpressionFactory
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public SqlServerSqlExpressionFactory(
- SqlExpressionFactoryDependencies dependencies,
- ISqlServerSingletonOptions sqlServerSingletonOptions)
+ SqlExpressionFactoryDependencies dependencies)
: base(dependencies)
{
_typeMappingSource = dependencies.TypeMappingSource;
- _sqlServerCompatibilityLevel = sqlServerSingletonOptions.CompatibilityLevel;
}
///
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlTranslatingExpressionVisitor.cs
index 677fe36f4ed..402b615a13e 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlTranslatingExpressionVisitor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlTranslatingExpressionVisitor.cs
@@ -21,7 +21,7 @@ public class SqlServerSqlTranslatingExpressionVisitor : RelationalSqlTranslating
private readonly SqlServerQueryCompilationContext _queryCompilationContext;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly IRelationalTypeMappingSource _typeMappingSource;
- private readonly int _sqlServerCompatibilityLevel;
+ private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions;
private static readonly HashSet DateTimeDataTypes
=
@@ -87,7 +87,7 @@ public SqlServerSqlTranslatingExpressionVisitor(
_queryCompilationContext = queryCompilationContext;
_sqlExpressionFactory = dependencies.SqlExpressionFactory;
_typeMappingSource = dependencies.TypeMappingSource;
- _sqlServerCompatibilityLevel = sqlServerSingletonOptions.CompatibilityLevel;
+ _sqlServerSingletonOptions = sqlServerSingletonOptions;
}
///
@@ -211,7 +211,9 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
// Translate non-aggregate string.Join to CONCAT_WS (for aggregate string.Join, see SqlServerStringAggregateMethodTranslator)
if (method == StringJoinMethodInfo
&& methodCallExpression.Arguments[1] is NewArrayExpression newArrayExpression
- && _sqlServerCompatibilityLevel >= 140)
+ && ((_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer && _sqlServerSingletonOptions.SqlServerCompatibilityLevel >= 140)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel >= 140)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSynapse)))
{
if (TranslationFailed(methodCallExpression.Arguments[0], Visit(methodCallExpression.Arguments[0]), out var delimiter))
{
@@ -533,7 +535,13 @@ private static string EscapeLikePattern(string pattern)
public override SqlExpression? GenerateGreatest(IReadOnlyList expressions, Type resultType)
{
// Docs: https://learn.microsoft.com/sql/t-sql/functions/logical-functions-greatest-transact-sql
- if (_sqlServerCompatibilityLevel < 160)
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer
+ && _sqlServerSingletonOptions.SqlServerCompatibilityLevel < 160)
+ {
+ return null;
+ }
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql
+ && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel < 160)
{
return null;
}
@@ -555,7 +563,13 @@ private static string EscapeLikePattern(string pattern)
public override SqlExpression? GenerateLeast(IReadOnlyList expressions, Type resultType)
{
// Docs: https://learn.microsoft.com/sql/t-sql/functions/logical-functions-least-transact-sql
- if (_sqlServerCompatibilityLevel < 160)
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer
+ && _sqlServerSingletonOptions.SqlServerCompatibilityLevel < 160)
+ {
+ return null;
+ }
+ if (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql
+ && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel < 160)
{
return null;
}
diff --git a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs
index 49064a8293d..f8dd1a44713 100644
--- a/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs
+++ b/src/EFCore.SqlServer/Query/Internal/Translators/SqlServerStringMethodTranslator.cs
@@ -202,7 +202,9 @@ public SqlServerStringMethodTranslator(ISqlExpressionFactory sqlExpressionFactor
// an overload that accepts the characters to trim.
if (method == TrimStartMethodInfoWithoutArgs
|| (method == TrimStartMethodInfoWithCharArrayArg && arguments[0] is SqlConstantExpression { Value: char[] { Length: 0 } })
- || (_sqlServerSingletonOptions.CompatibilityLevel >= 160
+ || (((_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer && _sqlServerSingletonOptions.SqlServerCompatibilityLevel >= 160)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel >= 160)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSynapse))
&& (method == TrimStartMethodInfoWithCharArg || method == TrimStartMethodInfoWithCharArrayArg)))
{
return ProcessTrimStartEnd(instance, arguments, "LTRIM");
@@ -210,7 +212,9 @@ public SqlServerStringMethodTranslator(ISqlExpressionFactory sqlExpressionFactor
if (method == TrimEndMethodInfoWithoutArgs
|| (method == TrimEndMethodInfoWithCharArrayArg && arguments[0] is SqlConstantExpression { Value: char[] { Length: 0 } })
- || (_sqlServerSingletonOptions.CompatibilityLevel >= 160
+ || (((_sqlServerSingletonOptions.EngineType == SqlServerEngineType.SqlServer && _sqlServerSingletonOptions.SqlServerCompatibilityLevel >= 160)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSql && _sqlServerSingletonOptions.AzureSqlCompatibilityLevel >= 160)
+ || (_sqlServerSingletonOptions.EngineType == SqlServerEngineType.AzureSynapse))
&& (method == TrimEndMethodInfoWithCharArg || method == TrimEndMethodInfoWithCharArrayArg)))
{
return ProcessTrimStartEnd(instance, arguments, "RTRIM");
diff --git a/test/EFCore.Design.Tests/Design/Internal/DbContextOperationsTest.cs b/test/EFCore.Design.Tests/Design/Internal/DbContextOperationsTest.cs
index 23375b644a6..68e7662ccef 100644
--- a/test/EFCore.Design.Tests/Design/Internal/DbContextOperationsTest.cs
+++ b/test/EFCore.Design.Tests/Design/Internal/DbContextOperationsTest.cs
@@ -270,7 +270,7 @@ public void GetContextInfo_returns_correct_info()
Assert.Equal("Test", info.DatabaseName);
Assert.Equal(@"(localdb)\mssqllocaldb", info.DataSource);
- Assert.Equal("None", info.Options);
+ Assert.Equal("EngineType=SqlServer", info.Options);
Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", info.ProviderName);
}
@@ -291,7 +291,7 @@ public void GetContextInfo_does_not_throw_if_DbConnection_cannot_be_created()
Assert.Equal(DesignStrings.BadConnection(expected.Message), info.DatabaseName);
Assert.Equal(DesignStrings.BadConnection(expected.Message), info.DataSource);
- Assert.Equal("None", info.Options);
+ Assert.Equal("EngineType=SqlServer", info.Options);
Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", info.ProviderName);
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/LoggingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/LoggingSqlServerTest.cs
index c73b6d512ae..64c82f18cdb 100644
--- a/test/EFCore.SqlServer.FunctionalTests/LoggingSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/LoggingSqlServerTest.cs
@@ -61,4 +61,7 @@ protected override string ProviderName
protected override string ProviderVersion
=> typeof(SqlServerOptionsExtension).Assembly
.GetCustomAttribute()?.InformationalVersion;
+
+ protected override string DefaultOptions
+ => "EngineType=SqlServer ";
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs
index ee806b4e0ab..c9f9b88881b 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs
@@ -4904,6 +4904,6 @@ protected override string StoreName
=> "ComplexNavigations160";
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(b => b.UseCompatibilityLevel(160));
+ => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs
index 83800b92c3b..d58c957f986 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs
@@ -8526,6 +8526,6 @@ protected override string StoreName
=> "ComplexNavigationsOwned160";
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(b => b.UseCompatibilityLevel(160));
+ => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServer160Test.cs
index c41575cf0ba..faaf2217203 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServer160Test.cs
@@ -1467,6 +1467,6 @@ private void AssertSql(params string[] expected)
public class Fixture160 : NorthwindQuerySqlServerFixture
{
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(b => b.UseCompatibilityLevel(160));
+ => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
index 555f1733719..6f0172d20f0 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
@@ -3008,6 +3008,6 @@ protected override void ClearLog()
public class Fixture160 : NorthwindQuerySqlServerFixture
{
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(b => b.UseCompatibilityLevel(160));
+ => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs
index b187615aee8..93022636239 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs
@@ -258,7 +258,7 @@ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder build
// TODO: Figure out if there's a nice way to continue using the retrying strategy
var sqlServerOptionsBuilder = new SqlServerDbContextOptionsBuilder(builder);
sqlServerOptionsBuilder
- .UseCompatibilityLevel(120)
+ .UseSqlServerCompatibilityLevel(120)
.ExecutionStrategy(d => new NonRetryingExecutionStrategy(d));
return builder;
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
index 5877a8c7c14..92b57f0d64d 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
@@ -1119,6 +1119,6 @@ protected override ITestStoreFactory TestStoreFactory
// Compatibility level 120 (SQL Server 2014) doesn't support OPENJSON
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(o => o.UseCompatibilityLevel(120));
+ => base.AddOptions(builder).UseSqlServer(o => o.UseSqlServerCompatibilityLevel(120));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs
index 09878bccedd..6d0e9f7bf9a 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs
@@ -1991,7 +1991,7 @@ protected override ITestStoreFactory TestStoreFactory
=> SqlServerTestStoreFactory.Instance;
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).UseSqlServer(b => b.UseCompatibilityLevel(160));
+ => base.AddOptions(builder).UseSqlServer(b => b.UseSqlServerCompatibilityLevel(160));
protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerConfigPatternsTest.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerConfigPatternsTest.cs
index d438844b951..26c498706f9 100644
--- a/test/EFCore.SqlServer.FunctionalTests/SqlServerConfigPatternsTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerConfigPatternsTest.cs
@@ -424,16 +424,16 @@ public class AzureSqlDatabase
[InlineData(true)]
[InlineData(false)]
[ConditionalTheory]
- public void Retry_on_failure_not_enabled_by_default_on_Azure_SQL(bool configured)
+ public void Retry_on_failure_not_enabled_by_default_on_Azure_SQL(bool useAzure)
{
- using var context = new NorthwindContext(configured);
+ using var context = new NorthwindContext(useAzure);
Assert.IsType(context.Database.CreateExecutionStrategy());
}
- private class NorthwindContext(bool configured) : DbContext
+ private class NorthwindContext(bool useAzure) : DbContext
{
- private readonly bool _azureConfigured = configured;
+ private readonly bool _useAzure = useAzure;
public DbSet Customers { get; set; }
@@ -444,9 +444,11 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
@"Server=test.database.windows.net:4040;Database=Test;ConnectRetryCount=0",
a =>
{
- if (_azureConfigured)
+ if (_useAzure)
{
+#pragma warning disable CS0618 // Type or member is obsolete
a.UseAzureSqlDefaults(false);
+#pragma warning restore CS0618 // Type or member is obsolete
}
});
@@ -460,10 +462,10 @@ public class NonDefaultAzureSqlDatabase
[InlineData(true)]
[InlineData(false)]
[ConditionalTheory]
- public void Retry_on_failure_enabled_if_Azure_SQL_configured(bool configured)
+ public void Retry_on_failure_enabled_if_Azure_SQL_configured(bool useAzure)
{
- using var context = new NorthwindContext(configured);
- if (configured)
+ using var context = new NorthwindContext(useAzure);
+ if (useAzure)
{
Assert.IsType(context.Database.CreateExecutionStrategy());
}
@@ -473,24 +475,302 @@ public void Retry_on_failure_enabled_if_Azure_SQL_configured(bool configured)
}
}
- private class NorthwindContext(bool azure) : DbContext
+ private class NorthwindContext(bool useAzure) : DbContext
{
- private readonly bool _isAzure = azure;
+ private readonly bool _useAzure = useAzure;
public DbSet Customers { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- => optionsBuilder
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false);
+ if (_useAzure)
+ {
+ optionsBuilder
+ .UseAzureSql(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString);
+ }
+ else
+ {
+ optionsBuilder
+ .UseSqlServer(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString);
+ }
+ }
+ }
+ }
+
+ public class ExplicitExecutionStrategies_SqlServer
+ {
+ [InlineData(true)]
+ [InlineData(false)]
+ [ConditionalTheory]
+ public void Retry_strategy_properly_handled(bool before)
+ {
+ using var context = new NorthwindContext(before);
+ if (before)
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ else
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ }
+
+ private class NorthwindContext(bool before) : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
.EnableServiceProviderCaching(false)
- .UseSqlServer(
- SqlServerNorthwindTestStoreFactory.NorthwindConnectionString,
- a =>
+ .UseSqlServer(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString,
+ b =>
{
- if (_isAzure)
+ if (before)
{
- a.UseAzureSqlDefaults();
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ b.EnableRetryOnFailure();
+ if (!before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
}
});
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+ public class ExplicitExecutionStrategies_AzureSql
+ {
+ [InlineData(true)]
+ [InlineData(false)]
+ [ConditionalTheory]
+ public void Retry_strategy_properly_handled(bool before)
+ {
+ using var context = new NorthwindContext(before);
+ if (before)
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ else
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ }
+
+ private class NorthwindContext(bool before) : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false)
+ .UseAzureSql(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString,
+ b =>
+ {
+ if (before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ b.EnableRetryOnFailure();
+ if (!before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ });
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+ public class ExplicitExecutionStrategies_AzureSynapse
+ {
+ [InlineData(true)]
+ [InlineData(false)]
+ [ConditionalTheory]
+ public void Retry_strategy_properly_handled(bool before)
+ {
+ using var context = new NorthwindContext(before);
+ if (before)
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ else
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ }
+
+ private class NorthwindContext(bool before) : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false)
+ .UseAzureSynapse(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString,
+ b =>
+ {
+ if (before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ b.EnableRetryOnFailure();
+ if (!before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ });
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+ public class ExplicitExecutionStrategies_ConfigureSqlEngine_AzureSql
+ {
+ [InlineData(true)]
+ [InlineData(false)]
+ [ConditionalTheory]
+ public void Retry_strategy_properly_handled(bool before)
+ {
+ using var context = new NorthwindContext(before);
+ if (before)
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ else
+ {
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+ }
+
+ private class NorthwindContext(bool before) : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false)
+ .ConfigureSqlEngine(
+ b =>
+ {
+ if (before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ b.EnableRetryOnFailure();
+ if (!before)
+ {
+ b.ExecutionStrategy(_ => new DummyExecutionStrategy());
+ }
+ })
+ .UseAzureSql();
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+
+ public class ConfigureTwoEngines
+ {
+ [Fact]
+ public void Throws_when_two_engines_used()
+ {
+ using var context = new NorthwindContext();
+ Assert.Throws(() => { _ = context.Model; });
+ }
+
+ private class NorthwindContext : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false)
+ .UseSqlServer()
+ .UseAzureSql();
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+
+ public class NoEngineConfigured
+ {
+ [Fact]
+ public void Throws_when_no_engine_configured()
+ {
+ using var context = new NorthwindContext();
+ Assert.Throws(() => { _ = context.Model; });
+ }
+
+ private class NorthwindContext : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder
+ .EnableServiceProviderCaching(false)
+ .ConfigureSqlEngine();
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ => ConfigureModel(modelBuilder);
+ }
+ }
+
+ public class AddConfigureDbContext
+ {
+ [Fact]
+ public void Does_not_throw_for_Add_Configure()
+ {
+ using var scope = new ServiceCollection()
+ .AddDbContext(b => b.UseSqlServer())
+ .ConfigureDbContext(b => b.ConfigureSqlEngine(o => o.EnableRetryOnFailure()))
+ .BuildServiceProvider(validateScopes: true)
+ .CreateScope();
+
+ var serviceProvider = scope.ServiceProvider;
+
+ var exception = Record.Exception(serviceProvider.GetRequiredService);
+ Assert.Null(exception);
+ }
+
+ [Fact]
+ public void Proper_execution_strategy()
+ {
+ using var scope = new ServiceCollection()
+ .AddDbContext(b => b.UseSqlServer())
+ .ConfigureDbContext(b => b.ConfigureSqlEngine(o => o.EnableRetryOnFailure()))
+ .BuildServiceProvider(validateScopes: true)
+ .CreateScope();
+
+ var serviceProvider = scope.ServiceProvider;
+
+ var context = serviceProvider.GetRequiredService();
+ Assert.IsType(context.Database.CreateExecutionStrategy());
+ }
+
+ private class NorthwindContext : DbContext
+ {
+ public DbSet Customers { get; set; }
+
+ public NorthwindContext(DbContextOptions options)
+ : base(options)
+ { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> ConfigureModel(modelBuilder);
@@ -516,4 +796,12 @@ private static void ConfigureModel(ModelBuilder builder)
b.HasKey(c => c.CustomerID);
b.ToTable("Customers");
});
+
+ private class DummyExecutionStrategy : IExecutionStrategy
+ {
+ public bool RetriesOnFailure => true;
+
+ public TResult Execute(TState state, Func operation, Func> verifySucceeded) => throw new NotImplementedException();
+ public Task ExecuteAsync(TState state, Func> operation, Func>> verifySucceeded, CancellationToken cancellationToken = default) => throw new NotImplementedException();
+ }
}
diff --git a/test/EFCore.SqlServer.Tests/SqlServerOptionsExtensionTest.cs b/test/EFCore.SqlServer.Tests/SqlServerOptionsExtensionTest.cs
index e1de681c655..38db2102555 100644
--- a/test/EFCore.SqlServer.Tests/SqlServerOptionsExtensionTest.cs
+++ b/test/EFCore.SqlServer.Tests/SqlServerOptionsExtensionTest.cs
@@ -52,13 +52,16 @@ public static IModel Instance
}
[ConditionalFact]
- public void ApplyServices_adds_SQL_server_services()
+ public void ApplyServices_adds_correct_services()
{
var services = new ServiceCollection();
- new SqlServerOptionsExtension().ApplyServices(services);
+ new SqlServerOptionsExtension()
+ .WithEngineType(SqlServerEngineType.SqlServer)
+ .ApplyServices(services);
Assert.Contains(services, sd => sd.ServiceType == typeof(ISqlServerConnection));
+ Assert.Contains(services, sd => sd.ServiceType == typeof(ISqlServerSingletonOptions));
}
private class ChangedRowNumberContext(bool setInternalServiceProvider) : DbContext