diff --git a/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs b/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs
index 45fd158b742..e5bc2f8e907 100644
--- a/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs
+++ b/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs
@@ -19,34 +19,20 @@ public class CommandEndEventData : CommandEventData
///
/// The event definition.
/// A delegate that generates a log message for this event.
- ///
- /// The .
- ///
- ///
- /// The method.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// Indicates whether or not the command was executed asynchronously.
- ///
- ///
- /// Indicates whether or not the application allows logging of parameter values.
- ///
- ///
- /// The start time of this event.
- ///
- ///
- /// The duration this event.
- ///
+ /// The .
+ /// The currently being used, to null if not known.
+ /// The method.
+ /// A correlation ID that identifies the instance being used.
+ /// A correlation ID that identifies the instance being used.
+ /// Indicates whether or not the command was executed asynchronously.
+ /// Indicates whether or not the application allows logging of parameter values.
+ /// The start time of this event.
+ /// The duration this event.
public CommandEndEventData(
[NotNull] EventDefinitionBase eventDefinition,
[NotNull] Func messageGenerator,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -54,7 +40,17 @@ public CommandEndEventData(
bool logParameterValues,
DateTimeOffset startTime,
TimeSpan duration)
- : base(eventDefinition, messageGenerator, command, executeMethod, commandId, connectionId, async, logParameterValues, startTime)
+ : base(
+ eventDefinition,
+ messageGenerator,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ logParameterValues,
+ startTime)
=> Duration = duration;
///
diff --git a/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs b/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs
index 2e0e0a697ce..ccf1e4445d4 100644
--- a/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs
+++ b/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs
@@ -18,37 +18,21 @@ public class CommandErrorEventData : CommandEndEventData, IErrorEventData
///
/// The event definition.
/// A delegate that generates a log message for this event.
- ///
- /// The that was executing when it failed.
- ///
- ///
- /// The method that was used to execute the command.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// The exception that was thrown when execution failed.
- ///
- ///
- /// Indicates whether or not the command was executed asynchronously.
- ///
- ///
- /// Indicates whether or not the application allows logging of parameter values.
- ///
- ///
- /// The start time of this event.
- ///
- ///
- /// The duration this event.
- ///
+ /// The that was executing when it failed.
+ /// The currently being used, to null if not known.
+ /// The method that was used to execute the command.
+ /// A correlation ID that identifies the instance being used.
+ /// A correlation ID that identifies the instance being used.
+ /// The exception that was thrown when execution failed.
+ /// Indicates whether or not the command was executed asynchronously.
+ /// Indicates whether or not the application allows logging of parameter values.
+ /// The start time of this event.
+ /// The duration this event.
public CommandErrorEventData(
[NotNull] EventDefinitionBase eventDefinition,
[NotNull] Func messageGenerator,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -57,7 +41,18 @@ public CommandErrorEventData(
bool logParameterValues,
DateTimeOffset startTime,
TimeSpan duration)
- : base(eventDefinition, messageGenerator, command, executeMethod, commandId, connectionId, async, logParameterValues, startTime, duration)
+ : base(
+ eventDefinition,
+ messageGenerator,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ logParameterValues,
+ startTime,
+ duration)
=> Exception = exception;
///
diff --git a/src/EFCore.Relational/Diagnostics/CommandEventData.cs b/src/EFCore.Relational/Diagnostics/CommandEventData.cs
index 7c9e039453f..8d3158c6ce3 100644
--- a/src/EFCore.Relational/Diagnostics/CommandEventData.cs
+++ b/src/EFCore.Relational/Diagnostics/CommandEventData.cs
@@ -12,45 +12,33 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics
/// The event payload for
/// command events.
///
- public class CommandEventData : EventData
+ public class CommandEventData : DbContextEventData
{
///
/// Constructs the event payload.
///
/// The event definition.
/// A delegate that generates a log message for this event.
- ///
- /// The .
- ///
- ///
- /// The method.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// Indicates whether or not the command was executed asynchronously.
- ///
- ///
- /// Indicates whether or not the application allows logging of parameter values.
- ///
- ///
- /// The start time of this event.
- ///
+ /// The .
+ /// The currently being used, to null if not known.
+ /// The method.
+ /// A correlation ID that identifies the instance being used.
+ /// A correlation ID that identifies the instance being used.
+ /// Indicates whether or not the command was executed asynchronously.
+ /// Indicates whether or not the application allows logging of parameter values.
+ /// The start time of this event.
public CommandEventData(
[NotNull] EventDefinitionBase eventDefinition,
[NotNull] Func messageGenerator,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
bool async,
bool logParameterValues,
DateTimeOffset startTime)
- : base(eventDefinition, messageGenerator)
+ : base(eventDefinition, messageGenerator, context)
{
Command = command;
CommandId = commandId;
diff --git a/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs b/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs
index d919a19bb52..16899fe8944 100644
--- a/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs
+++ b/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs
@@ -18,37 +18,21 @@ public class CommandExecutedEventData : CommandEndEventData
///
/// The event definition.
/// A delegate that generates a log message for this event.
- ///
- /// The that was executing when it failed.
- ///
- ///
- /// The method that was used to execute the command.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// A correlation ID that identifies the instance being used.
- ///
- ///
- /// The result of executing the operation.
- ///
- ///
- /// Indicates whether or not the command was executed asynchronously.
- ///
- ///
- /// Indicates whether or not the application allows logging of parameter values.
- ///
- ///
- /// The start time of this event.
- ///
- ///
- /// The duration this event.
- ///
+ /// The that was executing when it failed.
+ /// The currently being used, to null if not known.
+ /// The method that was used to execute the command.
+ /// A correlation ID that identifies the instance being used.
+ /// A correlation ID that identifies the instance being used.
+ /// The result of executing the operation.
+ /// Indicates whether or not the command was executed asynchronously.
+ /// Indicates whether or not the application allows logging of parameter values.
+ /// The start time of this event.
+ /// The duration this event.
public CommandExecutedEventData(
[NotNull] EventDefinitionBase eventDefinition,
[NotNull] Func messageGenerator,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -57,7 +41,18 @@ public CommandExecutedEventData(
bool logParameterValues,
DateTimeOffset startTime,
TimeSpan duration)
- : base(eventDefinition, messageGenerator, command, executeMethod, commandId, connectionId, async, logParameterValues, startTime, duration)
+ : base(
+ eventDefinition,
+ messageGenerator,
+ command,
+ context,
+ executeMethod,
+ commandId,
+ connectionId,
+ async,
+ logParameterValues,
+ startTime,
+ duration)
=> Result = result;
///
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
index ee9ae454bb8..39b10bb4d34 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
@@ -42,6 +42,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -49,6 +50,7 @@ public static class RelationalLoggerExtensions
public static InterceptionResult? CommandReaderExecuting(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime)
@@ -66,6 +68,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteReader,
commandId,
connectionId,
@@ -88,6 +91,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -95,6 +99,7 @@ public static class RelationalLoggerExtensions
public static InterceptionResult? CommandScalarExecuting(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime)
@@ -112,6 +117,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteScalar,
commandId,
connectionId,
@@ -134,6 +140,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -141,6 +148,7 @@ public static class RelationalLoggerExtensions
public static InterceptionResult? CommandNonQueryExecuting(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime)
@@ -158,6 +166,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteNonQuery,
commandId,
connectionId,
@@ -180,6 +189,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -188,6 +198,7 @@ public static class RelationalLoggerExtensions
public static Task?> CommandReaderExecutingAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime,
@@ -206,6 +217,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteReader,
commandId,
connectionId,
@@ -228,6 +240,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -236,6 +249,7 @@ public static class RelationalLoggerExtensions
public static Task?> CommandScalarExecutingAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime,
@@ -254,6 +268,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteScalar,
commandId,
connectionId,
@@ -276,6 +291,7 @@ public static class RelationalLoggerExtensions
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The time that execution began.
@@ -284,6 +300,7 @@ public static class RelationalLoggerExtensions
public static Task?> CommandNonQueryExecutingAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
DateTimeOffset startTime,
@@ -302,6 +319,7 @@ public static class RelationalLoggerExtensions
var eventData = BroadcastCommandExecuting(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteNonQuery,
commandId,
connectionId,
@@ -322,6 +340,7 @@ public static class RelationalLoggerExtensions
private static CommandEventData BroadcastCommandExecuting(
IDiagnosticsLogger diagnostics,
DbCommand command,
+ DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -334,6 +353,7 @@ private static CommandEventData BroadcastCommandExecuting(
definition,
CommandExecuting,
command,
+ context,
executeMethod,
commandId,
connectionId,
@@ -393,6 +413,7 @@ private static bool ShouldLogParameterValues(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -402,6 +423,7 @@ private static bool ShouldLogParameterValues(
public static DbDataReader CommandReaderExecuted(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
[CanBeNull] DbDataReader methodResult,
@@ -421,6 +443,7 @@ public static DbDataReader CommandReaderExecuted(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteReader,
commandId,
connectionId,
@@ -445,6 +468,7 @@ public static DbDataReader CommandReaderExecuted(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -454,6 +478,7 @@ public static DbDataReader CommandReaderExecuted(
public static object CommandScalarExecuted(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
[CanBeNull] object methodResult,
@@ -473,6 +498,7 @@ public static object CommandScalarExecuted(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteScalar,
commandId,
connectionId,
@@ -497,6 +523,7 @@ public static object CommandScalarExecuted(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -506,6 +533,7 @@ public static object CommandScalarExecuted(
public static int CommandNonQueryExecuted(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
int methodResult,
@@ -525,6 +553,7 @@ public static int CommandNonQueryExecuted(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteNonQuery,
commandId,
connectionId,
@@ -549,6 +578,7 @@ public static int CommandNonQueryExecuted(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -559,6 +589,7 @@ public static int CommandNonQueryExecuted(
public static Task CommandReaderExecutedAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
[CanBeNull] DbDataReader methodResult,
@@ -579,6 +610,7 @@ public static Task CommandReaderExecutedAsync(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteReader,
commandId,
connectionId,
@@ -603,6 +635,7 @@ public static Task CommandReaderExecutedAsync(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -613,6 +646,7 @@ public static Task CommandReaderExecutedAsync(
public static Task CommandScalarExecutedAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
[CanBeNull] object methodResult,
@@ -633,6 +667,7 @@ public static Task CommandScalarExecutedAsync(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteScalar,
commandId,
connectionId,
@@ -657,6 +692,7 @@ public static Task CommandScalarExecutedAsync(
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
/// The return value from the underlying method execution.
@@ -667,6 +703,7 @@ public static Task CommandScalarExecutedAsync(
public static Task CommandNonQueryExecutedAsync(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
Guid commandId,
Guid connectionId,
int methodResult,
@@ -687,6 +724,7 @@ public static Task CommandNonQueryExecutedAsync(
var eventData = BroadcastCommandExecuted(
diagnostics,
command,
+ context,
DbCommandMethod.ExecuteNonQuery,
commandId,
connectionId,
@@ -709,6 +747,7 @@ public static Task CommandNonQueryExecutedAsync(
private static CommandExecutedEventData BroadcastCommandExecuted(
IDiagnosticsLogger diagnostics,
DbCommand command,
+ DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -723,6 +762,7 @@ private static CommandExecutedEventData BroadcastCommandExecuted(
definition,
CommandExecuted,
command,
+ context,
executeMethod,
commandId,
connectionId,
@@ -781,6 +821,7 @@ private static string CommandExecuted(EventDefinitionBase definition, EventData
///
/// The diagnostics logger to use.
/// The database command object.
+ /// The currently being used, to null if not known.
/// Represents the method that will be called to execute the command.
/// The correlation ID associated with the given .
/// The correlation ID associated with the being used.
@@ -791,6 +832,7 @@ private static string CommandExecuted(EventDefinitionBase definition, EventData
public static void CommandError(
[NotNull] this IDiagnosticsLogger diagnostics,
[NotNull] DbCommand command,
+ [CanBeNull] DbContext context,
DbCommandMethod executeMethod,
Guid commandId,
Guid connectionId,
@@ -823,6 +865,7 @@ public static void CommandError(
definition,
CommandError,
command,
+ context,
executeMethod,
commandId,
connectionId,
diff --git a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs
index 4ce417943f8..11b2a3bc919 100644
--- a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs
@@ -208,21 +208,22 @@ public static int ExecuteSqlCommand(
Check.NotNull(sql, nameof(sql));
Check.NotNull(parameters, nameof(parameters));
- var concurrencyDetector = databaseFacade.GetService();
- var logger = databaseFacade.GetService>();
+ var concurrencyDetector = GetFacadeDependencies(databaseFacade).ConcurrencyDetector;
+ var logger = GetFacadeDependencies(databaseFacade).CommandLogger;
using (concurrencyDetector.EnterCriticalSection())
{
- var rawSqlCommand = databaseFacade
- .GetRelationalService()
+ var rawSqlCommand = GetFacadeDependencies(databaseFacade).RawSqlCommandBuilder
.Build(sql.Format, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteNonQuery(
- databaseFacade.GetRelationalService(),
- rawSqlCommand.ParameterValues,
- logger);
+ new RelationalCommandParameterObject(
+ GetFacadeDependencies(databaseFacade).RelationalConnection,
+ rawSqlCommand.ParameterValues,
+ ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context,
+ logger));
}
}
@@ -372,21 +373,23 @@ public static async Task ExecuteSqlCommandAsync(
Check.NotNull(sql, nameof(sql));
Check.NotNull(parameters, nameof(parameters));
- var concurrencyDetector = databaseFacade.GetService();
- var logger = databaseFacade.GetService>();
+ var facadeDependencies = GetFacadeDependencies(databaseFacade);
+ var concurrencyDetector = facadeDependencies.ConcurrencyDetector;
+ var logger = facadeDependencies.CommandLogger;
using (await concurrencyDetector.EnterCriticalSectionAsync(cancellationToken))
{
- var rawSqlCommand = databaseFacade
- .GetRelationalService()
+ var rawSqlCommand = GetFacadeDependencies(databaseFacade).RawSqlCommandBuilder
.Build(sql.Format, parameters);
return await rawSqlCommand
.RelationalCommand
.ExecuteNonQueryAsync(
- databaseFacade.GetRelationalService(),
- rawSqlCommand.ParameterValues,
- logger,
+ new RelationalCommandParameterObject(
+ facadeDependencies.RelationalConnection,
+ rawSqlCommand.ParameterValues,
+ ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context,
+ logger),
cancellationToken);
}
}
@@ -486,21 +489,23 @@ public static int ExecuteSqlRaw(
Check.NotNull(sql, nameof(sql));
Check.NotNull(parameters, nameof(parameters));
- var concurrencyDetector = databaseFacade.GetService();
- var logger = databaseFacade.GetService>();
+ var facadeDependencies = GetFacadeDependencies(databaseFacade);
+ var concurrencyDetector = facadeDependencies.ConcurrencyDetector;
+ var logger = facadeDependencies.CommandLogger;
using (concurrencyDetector.EnterCriticalSection())
{
- var rawSqlCommand = databaseFacade
- .GetRelationalService()
+ var rawSqlCommand = GetFacadeDependencies(databaseFacade).RawSqlCommandBuilder
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteNonQuery(
- databaseFacade.GetRelationalService(),
- rawSqlCommand.ParameterValues,
- logger);
+ new RelationalCommandParameterObject(
+ facadeDependencies.RelationalConnection,
+ rawSqlCommand.ParameterValues,
+ ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context,
+ logger));
}
}
@@ -636,21 +641,23 @@ public static async Task ExecuteSqlRawAsync(
Check.NotNull(sql, nameof(sql));
Check.NotNull(parameters, nameof(parameters));
- var concurrencyDetector = databaseFacade.GetService();
- var logger = databaseFacade.GetService>();
+ var facadeDependencies = GetFacadeDependencies(databaseFacade);
+ var concurrencyDetector = facadeDependencies.ConcurrencyDetector;
+ var logger = facadeDependencies.CommandLogger;
using (await concurrencyDetector.EnterCriticalSectionAsync(cancellationToken))
{
- var rawSqlCommand = databaseFacade
- .GetRelationalService()
+ var rawSqlCommand = GetFacadeDependencies(databaseFacade).RawSqlCommandBuilder
.Build(sql, parameters);
return await rawSqlCommand
.RelationalCommand
.ExecuteNonQueryAsync(
- databaseFacade.GetRelationalService(),
- rawSqlCommand.ParameterValues,
- logger,
+ new RelationalCommandParameterObject(
+ facadeDependencies.RelationalConnection,
+ rawSqlCommand.ParameterValues,
+ ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context,
+ logger),
cancellationToken);
}
}
@@ -661,7 +668,7 @@ public static async Task ExecuteSqlRawAsync(
/// The for the context.
/// The
public static DbConnection GetDbConnection([NotNull] this DatabaseFacade databaseFacade)
- => databaseFacade.GetRelationalService().DbConnection;
+ => GetFacadeDependencies(databaseFacade).RelationalConnection.DbConnection;
///
/// Opens the underlying .
@@ -670,7 +677,7 @@ public static DbConnection GetDbConnection([NotNull] this DatabaseFacade databas
public static void OpenConnection([NotNull] this DatabaseFacade databaseFacade)
=> databaseFacade.CreateExecutionStrategy().Execute(
databaseFacade, database
- => database.GetRelationalService().Open());
+ => GetFacadeDependencies(database).RelationalConnection.Open());
///
/// Opens the underlying .
@@ -685,14 +692,14 @@ public static Task OpenConnectionAsync(
CancellationToken cancellationToken = default)
=> databaseFacade.CreateExecutionStrategy().ExecuteAsync(
databaseFacade, (database, ct) =>
- database.GetRelationalService().OpenAsync(cancellationToken), cancellationToken);
+ GetFacadeDependencies(database).RelationalConnection.OpenAsync(cancellationToken), cancellationToken);
///
/// Closes the underlying .
///
/// The for the context.
public static void CloseConnection([NotNull] this DatabaseFacade databaseFacade)
- => databaseFacade.GetRelationalService().Close();
+ => GetFacadeDependencies(databaseFacade).RelationalConnection.Close();
///
/// Starts a new transaction with a given .
@@ -766,7 +773,7 @@ public static IDbContextTransaction UseTransaction(
/// The for the context.
/// The timeout to use, in seconds.
public static void SetCommandTimeout([NotNull] this DatabaseFacade databaseFacade, int? timeout)
- => databaseFacade.GetRelationalService().CommandTimeout = timeout;
+ => GetFacadeDependencies(databaseFacade).RelationalConnection.CommandTimeout = timeout;
///
///
@@ -806,7 +813,7 @@ public static void SetCommandTimeout([NotNull] this DatabaseFacade databaseFacad
/// The for the context.
/// The timeout, in seconds, or null if no timeout has been set.
public static int? GetCommandTimeout([NotNull] this DatabaseFacade databaseFacade)
- => databaseFacade.GetRelationalService().CommandTimeout;
+ => GetFacadeDependencies(databaseFacade).RelationalConnection.CommandTimeout;
///
/// Generates a script to create all tables for the current model.
@@ -817,6 +824,18 @@ public static void SetCommandTimeout([NotNull] this DatabaseFacade databaseFacad
public static string GenerateCreateScript([NotNull] this DatabaseFacade databaseFacade)
=> databaseFacade.GetRelationalService().GenerateCreateScript();
+ private static IRelationalDatabaseFacadeDependencies GetFacadeDependencies(DatabaseFacade databaseFacade)
+ {
+ var dependencies = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Dependencies;
+
+ if (dependencies is IRelationalDatabaseFacadeDependencies relationalDependencies)
+ {
+ return relationalDependencies;
+ }
+
+ throw new InvalidOperationException(RelationalStrings.RelationalNotInUse);
+ }
+
private static TService GetRelationalService(this IInfrastructure databaseFacade)
{
Check.NotNull(databaseFacade, nameof(databaseFacade));
@@ -831,6 +850,6 @@ private static TService GetRelationalService(this IInfrastructure Check.NotNull(databaseFacade, nameof(databaseFacade)).GetService();
+ => ((IDatabaseFacadeDependenciesAccessor)Check.NotNull(databaseFacade, nameof(databaseFacade))).Dependencies.TransactionManager;
}
}
diff --git a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
index 558f02c3b21..0c2c1dc75bf 100644
--- a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
+++ b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
@@ -76,6 +77,7 @@ public static readonly IDictionary RelationalServi
{ typeof(IMigrationsAssembly), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IBatchExecutor), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IRelationalConnection), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IRelationalDatabaseFacadeDependencies), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IRelationalDatabaseCreator), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IHistoryRepository), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(INamedConnectionStringResolver), new ServiceCharacteristics(ServiceLifetime.Scoped) },
@@ -153,6 +155,8 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd();
TryAdd();
TryAdd();
+ TryAdd(p => p.GetService());
+ TryAdd();
TryAdd();
TryAdd(p => p.GetService());
diff --git a/src/EFCore.Relational/Internal/IRelationalDatabaseFacadeDependencies.cs b/src/EFCore.Relational/Internal/IRelationalDatabaseFacadeDependencies.cs
new file mode 100644
index 00000000000..50a0462c029
--- /dev/null
+++ b/src/EFCore.Relational/Internal/IRelationalDatabaseFacadeDependencies.cs
@@ -0,0 +1,41 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.EntityFrameworkCore.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.
+ ///
+ ///
+ /// The service lifetime is . This means that each
+ /// instance will use its own instance of this service.
+ /// The implementation may depend on other services registered with any lifetime.
+ /// The implementation does not need to be thread-safe.
+ ///
+ ///
+ public interface IRelationalDatabaseFacadeDependencies : IDatabaseFacadeDependencies
+ {
+ ///
+ /// 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.
+ ///
+ IRelationalConnection RelationalConnection { 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.
+ ///
+ IRawSqlCommandBuilder RawSqlCommandBuilder { get; }
+ }
+}
diff --git a/src/EFCore.Relational/Internal/RelationalDatabaseFacadeDependencies.cs b/src/EFCore.Relational/Internal/RelationalDatabaseFacadeDependencies.cs
new file mode 100644
index 00000000000..75430a7a7df
--- /dev/null
+++ b/src/EFCore.Relational/Internal/RelationalDatabaseFacadeDependencies.cs
@@ -0,0 +1,56 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Storage;
+
+namespace Microsoft.EntityFrameworkCore.Internal
+{
+ public class RelationalDatabaseFacadeDependencies : DatabaseFacadeDependencies, IRelationalDatabaseFacadeDependencies
+ {
+ ///
+ /// 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 RelationalDatabaseFacadeDependencies(
+ [NotNull] IDbContextTransactionManager transactionManager,
+ [NotNull] IDatabaseCreator databaseCreator,
+ [NotNull] IExecutionStrategyFactory executionStrategyFactory,
+ [NotNull] IEnumerable databaseProviders,
+ [NotNull] IDiagnosticsLogger commandLogger,
+ [NotNull] IConcurrencyDetector concurrencyDetector,
+ [NotNull] IRelationalConnection relationalConnection,
+ [NotNull] IRawSqlCommandBuilder rawSqlCommandBuilder)
+ : base(
+ transactionManager,
+ databaseCreator,
+ executionStrategyFactory,
+ databaseProviders,
+ commandLogger,
+ concurrencyDetector)
+ {
+ RelationalConnection = relationalConnection;
+ RawSqlCommandBuilder = rawSqlCommandBuilder;
+ }
+
+ ///
+ /// 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 IRelationalConnection RelationalConnection { 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 virtual IRawSqlCommandBuilder RawSqlCommandBuilder { get; }
+ }
+}
diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs
index bb70c124047..9d4ade88ebb 100644
--- a/src/EFCore.Relational/Migrations/HistoryRepository.cs
+++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs
@@ -132,7 +132,12 @@ protected virtual string ProductVersionColumnName
public virtual bool Exists()
=> Dependencies.DatabaseCreator.Exists()
&& InterpretExistsResult(
- Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalar(Dependencies.Connection, null, Dependencies.CommandLogger));
+ Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalar(
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger)));
///
/// Checks whether or not the history table exists.
@@ -146,7 +151,12 @@ public virtual async Task ExistsAsync(CancellationToken cancellationToken
=> await Dependencies.DatabaseCreator.ExistsAsync(cancellationToken)
&& InterpretExistsResult(
await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync(
- Dependencies.Connection, null, Dependencies.CommandLogger, cancellationToken: cancellationToken));
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger),
+ cancellationToken));
///
/// Interprets the result of executing .
@@ -204,7 +214,12 @@ public virtual IReadOnlyList GetAppliedMigrations()
{
var command = Dependencies.RawSqlCommandBuilder.Build(GetAppliedMigrationsSql);
- using (var reader = command.ExecuteReader(Dependencies.Connection, null, Dependencies.CommandLogger))
+ using (var reader = command.ExecuteReader(
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger)))
{
while (reader.Read())
{
@@ -233,7 +248,13 @@ public virtual async Task> GetAppliedMigrationsAsync(
{
var command = Dependencies.RawSqlCommandBuilder.Build(GetAppliedMigrationsSql);
- using (var reader = await command.ExecuteReaderAsync(Dependencies.Connection, null, Dependencies.CommandLogger, cancellationToken: cancellationToken))
+ using (var reader = await command.ExecuteReaderAsync(
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger),
+ cancellationToken))
{
while (await reader.ReadAsync(cancellationToken))
{
diff --git a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
index 232a5a72057..b484ff5e9f6 100644
--- a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
+++ b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs
@@ -72,6 +72,7 @@ public sealed class HistoryRepositoryDependencies
/// Helpers for generating update SQL.
/// The convention set to use when creating the model.
/// The type mapper.
+ /// Contains the currently in use.
/// The logger for model building events.
/// The command logger.
[EntityFrameworkInternal]
@@ -85,6 +86,7 @@ public HistoryRepositoryDependencies(
[NotNull] ISqlGenerationHelper sqlGenerationHelper,
[NotNull] IConventionSetBuilder conventionSetBuilder,
[NotNull] IRelationalTypeMappingSource typeMappingSource,
+ [NotNull] ICurrentDbContext currentDbContext,
[NotNull] IDiagnosticsLogger modelLogger,
[NotNull] IDiagnosticsLogger commandLogger)
{
@@ -97,6 +99,7 @@ public HistoryRepositoryDependencies(
Check.NotNull(sqlGenerationHelper, nameof(sqlGenerationHelper));
Check.NotNull(conventionSetBuilder, nameof(conventionSetBuilder));
Check.NotNull(typeMappingSource, nameof(typeMappingSource));
+ Check.NotNull(currentDbContext, nameof(currentDbContext));
Check.NotNull(modelLogger, nameof(modelLogger));
Check.NotNull(commandLogger, nameof(commandLogger));
@@ -109,6 +112,7 @@ public HistoryRepositoryDependencies(
SqlGenerationHelper = sqlGenerationHelper;
ConventionSetBuilder = conventionSetBuilder;
TypeMappingSource = typeMappingSource;
+ CurrentDbContext = currentDbContext;
ModelLogger = modelLogger;
CommandLogger = commandLogger;
}
@@ -158,6 +162,11 @@ public HistoryRepositoryDependencies(
///
public IRelationalTypeMappingSource TypeMappingSource { get; }
+ ///
+ /// Contains the currently in use.
+ ///
+ public ICurrentDbContext CurrentDbContext { get; }
+
///
/// The model logger
///
@@ -184,6 +193,7 @@ public HistoryRepositoryDependencies With([NotNull] IRelationalDatabaseCreator d
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -203,6 +213,7 @@ public HistoryRepositoryDependencies With([NotNull] IRawSqlCommandBuilder rawSql
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -222,6 +233,7 @@ public HistoryRepositoryDependencies With([NotNull] IRelationalConnection connec
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -241,6 +253,7 @@ public HistoryRepositoryDependencies With([NotNull] IDbContextOptions options)
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -260,6 +273,7 @@ public HistoryRepositoryDependencies With([NotNull] IMigrationsModelDiffer model
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -279,6 +293,7 @@ public HistoryRepositoryDependencies With([NotNull] IMigrationsSqlGenerator migr
SqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -298,6 +313,7 @@ public HistoryRepositoryDependencies With([NotNull] ISqlGenerationHelper sqlGene
sqlGenerationHelper,
ConventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -317,6 +333,7 @@ public HistoryRepositoryDependencies With([NotNull] IConventionSetBuilder conven
SqlGenerationHelper,
conventionSetBuilder,
TypeMappingSource,
+ CurrentDbContext,
ModelLogger,
CommandLogger);
@@ -336,6 +353,27 @@ public HistoryRepositoryDependencies With([NotNull] IRelationalTypeMappingSource
SqlGenerationHelper,
ConventionSetBuilder,
typeMappingSource,
+ CurrentDbContext,
+ ModelLogger,
+ CommandLogger);
+
+ ///
+ /// Clones this dependency parameter object with one service replaced.
+ ///
+ /// The type mapper.
+ /// A new parameter object with the given service replaced.
+ public HistoryRepositoryDependencies With([NotNull] ICurrentDbContext currentDbContext)
+ => new HistoryRepositoryDependencies(
+ DatabaseCreator,
+ RawSqlCommandBuilder,
+ Connection,
+ Options,
+ ModelDiffer,
+ MigrationsSqlGenerator,
+ SqlGenerationHelper,
+ ConventionSetBuilder,
+ TypeMappingSource,
+ currentDbContext,
ModelLogger,
CommandLogger);
@@ -355,6 +393,7 @@ public HistoryRepositoryDependencies With([NotNull] IDiagnosticsLogger _logger;
private readonly IDiagnosticsLogger _commandLogger;
private readonly string _activeProvider;
@@ -59,6 +61,7 @@ public Migrator(
[NotNull] IMigrationCommandExecutor migrationCommandExecutor,
[NotNull] IRelationalConnection connection,
[NotNull] ISqlGenerationHelper sqlGenerationHelper,
+ [NotNull] ICurrentDbContext currentDbContext,
[NotNull] IDiagnosticsLogger logger,
[NotNull] IDiagnosticsLogger commandLogger,
[NotNull] IDatabaseProvider databaseProvider)
@@ -71,6 +74,7 @@ public Migrator(
Check.NotNull(migrationCommandExecutor, nameof(migrationCommandExecutor));
Check.NotNull(connection, nameof(connection));
Check.NotNull(sqlGenerationHelper, nameof(sqlGenerationHelper));
+ Check.NotNull(currentDbContext, nameof(currentDbContext));
Check.NotNull(logger, nameof(logger));
Check.NotNull(commandLogger, nameof(commandLogger));
Check.NotNull(databaseProvider, nameof(databaseProvider));
@@ -83,6 +87,7 @@ public Migrator(
_migrationCommandExecutor = migrationCommandExecutor;
_connection = connection;
_sqlGenerationHelper = sqlGenerationHelper;
+ _currentDbContext = currentDbContext;
_logger = logger;
_commandLogger = commandLogger;
_activeProvider = databaseProvider.Name;
@@ -108,7 +113,12 @@ public virtual void Migrate(string targetMigration = null)
var command = _rawSqlCommandBuilder.Build(
_historyRepository.GetCreateScript());
- command.ExecuteNonQuery(_connection, null, _commandLogger);
+ command.ExecuteNonQuery(
+ new RelationalCommandParameterObject(
+ _connection,
+ null,
+ _currentDbContext.Context,
+ _commandLogger));
}
var commandLists = GetMigrationCommandLists(_historyRepository.GetAppliedMigrations(), targetMigration);
@@ -140,7 +150,13 @@ public virtual async Task MigrateAsync(
var command = _rawSqlCommandBuilder.Build(
_historyRepository.GetCreateScript());
- await command.ExecuteNonQueryAsync(_connection, null, _commandLogger, cancellationToken: cancellationToken);
+ await command.ExecuteNonQueryAsync(
+ new RelationalCommandParameterObject(
+ _connection,
+ null,
+ _currentDbContext.Context,
+ _commandLogger),
+ cancellationToken);
}
var commandLists = GetMigrationCommandLists(
@@ -382,7 +398,7 @@ protected virtual IReadOnlyList GenerateUpSql([NotNull] Migrat
return _migrationsSqlGenerator
.Generate(migration.UpOperations, migration.TargetModel)
- .Concat(new[] { new MigrationCommand(insertCommand, _commandLogger) })
+ .Concat(new[] { new MigrationCommand(insertCommand, _currentDbContext.Context, _commandLogger) })
.ToList();
}
@@ -403,7 +419,7 @@ protected virtual IReadOnlyList GenerateDownSql(
return _migrationsSqlGenerator
.Generate(migration.DownOperations, previousMigration?.TargetModel)
- .Concat(new[] { new MigrationCommand(deleteCommand, _commandLogger) })
+ .Concat(new[] { new MigrationCommand(deleteCommand, _currentDbContext.Context, _commandLogger) })
.ToList();
}
}
diff --git a/src/EFCore.Relational/Migrations/MigrationCommand.cs b/src/EFCore.Relational/Migrations/MigrationCommand.cs
index 66f2c8aa4b7..752414b149e 100644
--- a/src/EFCore.Relational/Migrations/MigrationCommand.cs
+++ b/src/EFCore.Relational/Migrations/MigrationCommand.cs
@@ -17,22 +17,26 @@ namespace Microsoft.EntityFrameworkCore.Migrations
public class MigrationCommand
{
private readonly IRelationalCommand _relationalCommand;
+ private readonly DbContext _context;
private readonly IDiagnosticsLogger _logger;
///
/// Creates a new instance of the command.
///
/// The underlying that will be used to execute the command.
+ /// The current or null if not known.
/// The command logger.
/// Indicates whether or not transactions should be suppressed while executing the command.
public MigrationCommand(
[NotNull] IRelationalCommand relationalCommand,
+ [CanBeNull] DbContext context,
[NotNull] IDiagnosticsLogger logger,
bool transactionSuppressed = false)
{
Check.NotNull(relationalCommand, nameof(relationalCommand));
_relationalCommand = relationalCommand;
+ _context = context;
_logger = logger;
TransactionSuppressed = transactionSuppressed;
}
@@ -57,9 +61,11 @@ public virtual int ExecuteNonQuery(
[NotNull] IRelationalConnection connection,
[CanBeNull] IReadOnlyDictionary parameterValues = null)
=> _relationalCommand.ExecuteNonQuery(
- Check.NotNull(connection, nameof(connection)),
- parameterValues,
- _logger);
+ new RelationalCommandParameterObject(
+ connection,
+ parameterValues,
+ _context,
+ _logger));
///
/// Executes the command and returns the number of rows affected.
@@ -73,9 +79,11 @@ public virtual Task ExecuteNonQueryAsync(
[CanBeNull] IReadOnlyDictionary parameterValues = null,
CancellationToken cancellationToken = default)
=> _relationalCommand.ExecuteNonQueryAsync(
- Check.NotNull(connection, nameof(connection)),
- parameterValues,
- _logger,
+ new RelationalCommandParameterObject(
+ connection,
+ parameterValues,
+ _context,
+ _logger),
cancellationToken);
}
}
diff --git a/src/EFCore.Relational/Migrations/MigrationCommandListBuilder.cs b/src/EFCore.Relational/Migrations/MigrationCommandListBuilder.cs
index b0388be2f02..079d56aae10 100644
--- a/src/EFCore.Relational/Migrations/MigrationCommandListBuilder.cs
+++ b/src/EFCore.Relational/Migrations/MigrationCommandListBuilder.cs
@@ -51,7 +51,13 @@ public virtual MigrationCommandListBuilder EndCommand(bool suppressTransaction =
{
if (_commandBuilder.CommandTextLength != 0)
{
- _commands.Add(new MigrationCommand(_commandBuilder.Build(), _dependencies.Logger, suppressTransaction));
+ _commands.Add(
+ new MigrationCommand(
+ _commandBuilder.Build(),
+ _dependencies.CurrentDbContext.Context,
+ _dependencies.Logger,
+ suppressTransaction));
+
_commandBuilder = _dependencies.CommandBuilderFactory.Create();
}
diff --git a/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs b/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
index 59f1b7ea95f..e6a7ecb7707 100644
--- a/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
+++ b/src/EFCore.Relational/Migrations/MigrationsSqlGeneratorDependencies.cs
@@ -59,6 +59,7 @@ public sealed class MigrationsSqlGeneratorDependencies
/// High level SQL generator.
/// Helpers for SQL generation.
/// The type mapper.
+ /// Contains the currently in use.
/// A logger.
[EntityFrameworkInternal]
public MigrationsSqlGeneratorDependencies(
@@ -66,18 +67,21 @@ public MigrationsSqlGeneratorDependencies(
[NotNull] IUpdateSqlGenerator updateSqlGenerator,
[NotNull] ISqlGenerationHelper sqlGenerationHelper,
[NotNull] IRelationalTypeMappingSource typeMappingSource,
+ [NotNull] ICurrentDbContext currentDbContext,
[NotNull] IDiagnosticsLogger logger)
{
Check.NotNull(commandBuilderFactory, nameof(commandBuilderFactory));
Check.NotNull(updateSqlGenerator, nameof(updateSqlGenerator));
Check.NotNull(sqlGenerationHelper, nameof(sqlGenerationHelper));
Check.NotNull(typeMappingSource, nameof(typeMappingSource));
+ Check.NotNull(currentDbContext, nameof(currentDbContext));
Check.NotNull(logger, nameof(logger));
CommandBuilderFactory = commandBuilderFactory;
SqlGenerationHelper = sqlGenerationHelper;
UpdateSqlGenerator = updateSqlGenerator;
TypeMappingSource = typeMappingSource;
+ CurrentDbContext = currentDbContext;
Logger = logger;
}
@@ -101,6 +105,11 @@ public MigrationsSqlGeneratorDependencies(
///
public IRelationalTypeMappingSource TypeMappingSource { get; }
+ ///
+ /// Contains the currently in use.
+ ///
+ public ICurrentDbContext CurrentDbContext { get; }
+
///
/// A logger.
///
@@ -117,6 +126,7 @@ public MigrationsSqlGeneratorDependencies With([NotNull] IRelationalCommandBuild
UpdateSqlGenerator,
SqlGenerationHelper,
TypeMappingSource,
+ CurrentDbContext,
Logger);
///
@@ -130,6 +140,7 @@ public MigrationsSqlGeneratorDependencies With([NotNull] IUpdateSqlGenerator upd
updateSqlGenerator,
SqlGenerationHelper,
TypeMappingSource,
+ CurrentDbContext,
Logger);
///
@@ -143,6 +154,7 @@ public MigrationsSqlGeneratorDependencies With([NotNull] ISqlGenerationHelper sq
UpdateSqlGenerator,
sqlGenerationHelper,
TypeMappingSource,
+ CurrentDbContext,
Logger);
///
@@ -156,6 +168,21 @@ public MigrationsSqlGeneratorDependencies With([NotNull] IRelationalTypeMappingS
UpdateSqlGenerator,
SqlGenerationHelper,
typeMappingSource,
+ CurrentDbContext,
+ Logger);
+
+ ///
+ /// Clones this dependency parameter object with one service replaced.
+ ///
+ /// A replacement for the current dependency of this type.
+ /// A new parameter object with the given service replaced.
+ public MigrationsSqlGeneratorDependencies With([NotNull] ICurrentDbContext currentDbContext)
+ => new MigrationsSqlGeneratorDependencies(
+ CommandBuilderFactory,
+ UpdateSqlGenerator,
+ SqlGenerationHelper,
+ TypeMappingSource,
+ currentDbContext,
Logger);
///
@@ -169,6 +196,7 @@ public MigrationsSqlGeneratorDependencies With([NotNull] IDiagnosticsLogger MoveNextAsync()
_dataReader
= await relationalCommand.ExecuteReaderAsync(
- _relationalQueryContext.Connection,
- _relationalQueryContext.ParameterValues,
- _relationalQueryContext.CommandLogger,
+ new RelationalCommandParameterObject(
+ _relationalQueryContext.Connection,
+ _relationalQueryContext.ParameterValues,
+ _relationalQueryContext.Context,
+ _relationalQueryContext.CommandLogger),
_cancellationToken);
if (selectExpression.IsNonComposedFromSql())
diff --git a/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs b/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs
index f4ba2951745..69806e6746a 100644
--- a/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs
+++ b/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs
@@ -93,9 +93,11 @@ public bool MoveNext()
_dataReader
= relationalCommand.ExecuteReader(
- _relationalQueryContext.Connection,
- _relationalQueryContext.ParameterValues,
- _relationalQueryContext.CommandLogger);
+ new RelationalCommandParameterObject(
+ _relationalQueryContext.Connection,
+ _relationalQueryContext.ParameterValues,
+ _relationalQueryContext.Context,
+ _relationalQueryContext.CommandLogger));
if (selectExpression.IsNonComposedFromSql())
{
diff --git a/src/EFCore.Relational/Storage/IRelationalCommand.cs b/src/EFCore.Relational/Storage/IRelationalCommand.cs
index ba4fd262880..f508fb367c6 100644
--- a/src/EFCore.Relational/Storage/IRelationalCommand.cs
+++ b/src/EFCore.Relational/Storage/IRelationalCommand.cs
@@ -4,8 +4,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using JetBrains.Annotations;
-using Microsoft.EntityFrameworkCore.Diagnostics;
namespace Microsoft.EntityFrameworkCore.Storage
{
@@ -33,85 +31,58 @@ public interface IRelationalCommand
///
/// Executes the command with no results.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// The number of rows affected.
- int ExecuteNonQuery(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger);
+ int ExecuteNonQuery(RelationalCommandParameterObject parameterObject);
///
/// Asynchronously executes the command with no results.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// A to observe while waiting for the task to complete.
///
/// A task that represents the asynchronous operation. The task result contains the number of rows affected.
///
Task ExecuteNonQueryAsync(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default);
///
/// Executes the command with a single scalar result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// The result of the command.
- object ExecuteScalar(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger);
+ object ExecuteScalar(RelationalCommandParameterObject parameterObject);
///
/// Asynchronously executes the command with a single scalar result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// A to observe while waiting for the task to complete.
///
/// A task that represents the asynchronous operation. The task result contains the result of the command.
///
Task ExecuteScalarAsync(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default);
///
/// Executes the command with a result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// The result of the command.
- RelationalDataReader ExecuteReader(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger);
+ RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject);
///
/// Asynchronously executes the command with a result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// A to observe while waiting for the task to complete.
///
/// A task that represents the asynchronous operation. The task result contains the result of the command.
///
Task ExecuteReaderAsync(
- [NotNull] IRelationalConnection connection,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [NotNull] IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default);
}
}
diff --git a/src/EFCore.Relational/Storage/RelationalCommand.cs b/src/EFCore.Relational/Storage/RelationalCommand.cs
index 6f477571c65..7b74a909781 100644
--- a/src/EFCore.Relational/Storage/RelationalCommand.cs
+++ b/src/EFCore.Relational/Storage/RelationalCommand.cs
@@ -26,7 +26,7 @@ public class RelationalCommand : IRelationalCommand
{
///
///
- /// Constructs a new .
+ /// Constructs a new .
///
///
/// This type is typically used by database providers (and other extensions). It is generally
@@ -68,223 +68,331 @@ public RelationalCommand(
///
/// Executes the command with no results.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// The number of rows affected.
- public virtual int ExecuteNonQuery(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
- => (int)Execute(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteNonQuery,
- parameterValues,
- logger);
+ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
+ {
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
+
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
+
+ connection.Open();
+
+ var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+ var stopwatch = Stopwatch.StartNew();
+ try
+ {
+ var nonQueryResult = (logger?.CommandNonQueryExecuting(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime: startTime)
+ ?? new InterceptionResult(command.ExecuteNonQuery())).Result;
+
+ return logger?.CommandNonQueryExecuted(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ nonQueryResult,
+ startTime,
+ stopwatch.Elapsed)
+ ?? nonQueryResult;
+ }
+ catch (Exception exception)
+ {
+ logger?.CommandError(
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connection.ConnectionId,
+ exception,
+ false,
+ startTime,
+ stopwatch.Elapsed);
+
+ throw;
+ }
+ finally
+ {
+ CleanupCommand(command, connection);
+ }
+ }
+
+ private static void CleanupCommand(
+ DbCommand dbCommand,
+ IRelationalConnection connection)
+ {
+ dbCommand.Parameters.Clear();
+ dbCommand.Dispose();
+ connection.Close();
+ }
///
/// Asynchronously executes the command with no results.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// A to observe while waiting for the task to complete.
///
/// A task that represents the asynchronous operation. The task result contains the number of rows affected.
///
- public virtual Task ExecuteNonQueryAsync(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ public virtual async Task ExecuteNonQueryAsync(
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
- => ExecuteAsync(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteNonQuery,
- parameterValues,
- logger,
- cancellationToken).Cast();
+ {
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
+
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
+
+ await connection.OpenAsync(cancellationToken);
+
+ var commandId = Guid.NewGuid();
+
+ var startTime = DateTimeOffset.UtcNow;
+ var stopwatch = Stopwatch.StartNew();
+ try
+ {
+ var interceptionResult = logger == null
+ ? null
+ : await logger.CommandNonQueryExecutingAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime,
+ cancellationToken);
+
+ var result = interceptionResult.HasValue
+ ? interceptionResult.Value.Result
+ : await command.ExecuteNonQueryAsync(cancellationToken);
+
+ if (logger != null)
+ {
+ result = await logger.CommandNonQueryExecutedAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ result,
+ startTime,
+ stopwatch.Elapsed,
+ cancellationToken);
+ }
+
+ return result;
+ }
+ catch (Exception exception)
+ {
+ logger?.CommandError(
+ command,
+ context,
+ DbCommandMethod.ExecuteNonQuery,
+ commandId,
+ connection.ConnectionId,
+ exception,
+ true,
+ startTime,
+ stopwatch.Elapsed);
+
+ throw;
+ }
+ finally
+ {
+ CleanupCommand(command, connection);
+ }
+ }
///
/// Executes the command with a single scalar result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// The result of the command.
- public virtual object ExecuteScalar(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
- => Execute(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteScalar,
- parameterValues,
- logger);
+ public virtual object ExecuteScalar(RelationalCommandParameterObject parameterObject)
+ {
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
+
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
+
+ connection.Open();
+
+ var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+ var stopwatch = Stopwatch.StartNew();
+ try
+ {
+ var result = (logger?.CommandScalarExecuting(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime)
+ ?? new InterceptionResult(command.ExecuteScalar())).Result;
+
+ return logger?.CommandScalarExecuted(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ result,
+ startTime,
+ stopwatch.Elapsed)
+ ?? result;
+ }
+ catch (Exception exception)
+ {
+ logger?.CommandError(
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connection.ConnectionId,
+ exception,
+ false,
+ startTime,
+ stopwatch.Elapsed);
+
+ throw;
+ }
+ finally
+ {
+ CleanupCommand(command, connection);
+ }
+ }
///
/// Asynchronously executes the command with a single scalar result.
///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
+ /// Parameters for this method.
/// A to observe while waiting for the task to complete.
///
/// A task that represents the asynchronous operation. The task result contains the result of the command.
///
- public virtual Task ExecuteScalarAsync(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ public virtual async Task ExecuteScalarAsync(
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
- => ExecuteAsync(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteScalar,
- parameterValues,
- logger,
- cancellationToken);
+ {
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- ///
- /// Executes the command with a result.
- ///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
- /// The result of the command.
- public virtual RelationalDataReader ExecuteReader(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
- => (RelationalDataReader)Execute(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteReader,
- parameterValues,
- logger);
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
- ///
- /// Asynchronously executes the command with a result.
- ///
- /// The connection to execute against.
- /// The values for the parameters.
- /// The command logger.
- /// A to observe while waiting for the task to complete.
- ///
- /// A task that represents the asynchronous operation. The task result contains the result of the command.
- ///
- public virtual Task ExecuteReaderAsync(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
- CancellationToken cancellationToken = default)
- => ExecuteAsync(
- Check.NotNull(connection, nameof(connection)),
- DbCommandMethod.ExecuteReader,
- parameterValues,
- logger,
- cancellationToken).Cast();
+ await connection.OpenAsync(cancellationToken);
+
+ var commandId = Guid.NewGuid();
+ var startTime = DateTimeOffset.UtcNow;
+ var stopwatch = Stopwatch.StartNew();
+
+ try
+ {
+ var interceptionResult = logger == null
+ ? null
+ : await logger.CommandScalarExecutingAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime,
+ cancellationToken);
+
+ var result = interceptionResult.HasValue
+ ? interceptionResult.Value.Result
+ : await command.ExecuteScalarAsync(cancellationToken);
+
+ if (logger != null)
+ {
+ result = await logger.CommandScalarExecutedAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ result,
+ startTime,
+ stopwatch.Elapsed,
+ cancellationToken);
+ }
+
+ return result;
+ }
+ catch (Exception exception)
+ {
+ logger?.CommandError(
+ command,
+ context,
+ DbCommandMethod.ExecuteScalar,
+ commandId,
+ connection.ConnectionId,
+ exception,
+ true,
+ startTime,
+ stopwatch.Elapsed);
+
+ throw;
+ }
+ finally
+ {
+ CleanupCommand(command, connection);
+ }
+ }
///
- /// The method called by other methods on this type to execute synchronously.
+ /// Executes the command with a result.
///
- /// The connection to use.
- /// The method type.
- /// The parameter values.
- /// The command logger.
- /// The result of the execution.
- protected virtual object Execute(
- [NotNull] IRelationalConnection connection,
- DbCommandMethod executeMethod,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger)
+ /// Parameters for this method.
+ /// The result of the command.
+ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject)
{
- Check.NotNull(connection, nameof(connection));
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var dbCommand = CreateCommand(connection, parameterValues);
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
connection.Open();
var commandId = Guid.NewGuid();
-
var startTime = DateTimeOffset.UtcNow;
var stopwatch = Stopwatch.StartNew();
- object result;
var readerOpen = false;
try
{
- switch (executeMethod)
+ var reader = (logger?.CommandReaderExecuting(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime)
+ ?? new InterceptionResult(command.ExecuteReader())).Result;
+
+ if (logger != null)
{
- case DbCommandMethod.ExecuteNonQuery:
- var nonQueryResult = (logger?.CommandNonQueryExecuting(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime)
- ?? new InterceptionResult(dbCommand.ExecuteNonQuery())).Result;
-
- result = logger?.CommandNonQueryExecuted(
- dbCommand,
- commandId,
- connection.ConnectionId,
- nonQueryResult,
- startTime,
- stopwatch.Elapsed)
- ?? nonQueryResult;
-
- break;
- case DbCommandMethod.ExecuteScalar:
- var scalarResult = (logger?.CommandScalarExecuting(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime)
- ?? new InterceptionResult(dbCommand.ExecuteScalar())).Result;
-
- result = logger?.CommandScalarExecuted(
- dbCommand,
- commandId,
- connection.ConnectionId,
- scalarResult,
- startTime,
- stopwatch.Elapsed)
- ?? scalarResult;
- break;
- case DbCommandMethod.ExecuteReader:
- var reader = (logger?.CommandReaderExecuting(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime)
- ?? new InterceptionResult(dbCommand.ExecuteReader())).Result;
-
- if (logger != null)
- {
- reader = logger?.CommandReaderExecuted(
- dbCommand,
- commandId,
- connection.ConnectionId,
- reader,
- startTime,
- stopwatch.Elapsed);
- }
-
- result = new RelationalDataReader(
- connection,
- dbCommand,
- reader,
- commandId,
- logger);
-
- readerOpen = true;
- break;
- default:
- throw new NotSupportedException();
+ reader = logger.CommandReaderExecuted(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ reader,
+ startTime,
+ stopwatch.Elapsed);
}
+
+ var result = new RelationalDataReader(
+ connection,
+ command,
+ reader,
+ commandId,
+ logger);
+
+ readerOpen = true;
+
+ return result;
}
catch (Exception exception)
{
logger?.CommandError(
- dbCommand,
- executeMethod,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
commandId,
connection.ConnectionId,
exception,
@@ -298,149 +406,80 @@ protected virtual object Execute(
{
if (!readerOpen)
{
- dbCommand.Parameters.Clear();
- dbCommand.Dispose();
- connection.Close();
+ CleanupCommand(command, connection);
}
}
-
- return result;
}
///
- /// The method called by other methods on this type to execute synchronously.
+ /// Asynchronously executes the command with a result.
///
- /// The connection to use.
- /// The method type.
- /// The parameter values.
- /// The command logger.
- /// The cancellation token.
- /// The result of the execution.
- protected virtual async Task ExecuteAsync(
- [NotNull] IRelationalConnection connection,
- DbCommandMethod executeMethod,
- [CanBeNull] IReadOnlyDictionary parameterValues,
- [CanBeNull] IDiagnosticsLogger logger,
+ /// Parameters for this method.
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// A task that represents the asynchronous operation. The task result contains the result of the command.
+ ///
+ public virtual async Task ExecuteReaderAsync(
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
{
- Check.NotNull(connection, nameof(connection));
+ var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
- var dbCommand = CreateCommand(connection, parameterValues);
+ var command = CreateCommand(connection, parameterObject.ParameterValues);
await connection.OpenAsync(cancellationToken);
var commandId = Guid.NewGuid();
-
var startTime = DateTimeOffset.UtcNow;
var stopwatch = Stopwatch.StartNew();
- object result;
var readerOpen = false;
try
{
- switch (executeMethod)
+ var interceptionResult = logger == null
+ ? null
+ : await logger.CommandReaderExecutingAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ startTime,
+ cancellationToken);
+
+ var reader = interceptionResult.HasValue
+ ? interceptionResult.Value.Result
+ : await command.ExecuteReaderAsync(cancellationToken);
+
+ if (logger != null)
{
- case DbCommandMethod.ExecuteNonQuery:
- var nonQueryResult = logger == null
- ? null
- : await logger.CommandNonQueryExecutingAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime,
- cancellationToken);
-
- var nonQueryValue = nonQueryResult.HasValue
- ? nonQueryResult.Value.Result
- : await dbCommand.ExecuteNonQueryAsync(cancellationToken);
-
- if (logger != null)
- {
- nonQueryValue = await logger.CommandNonQueryExecutedAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- nonQueryValue,
- startTime,
- stopwatch.Elapsed,
- cancellationToken);
- }
-
- result = nonQueryValue;
- break;
- case DbCommandMethod.ExecuteScalar:
- var scalarResult = logger == null
- ? null
- : await logger.CommandScalarExecutingAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime,
- cancellationToken);
-
- var scalarValue = scalarResult.HasValue
- ? scalarResult.Value.Result
- : await dbCommand.ExecuteScalarAsync(cancellationToken);
-
- if (logger != null)
- {
- scalarValue = await logger.CommandScalarExecutedAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- scalarValue,
- startTime,
- stopwatch.Elapsed,
- cancellationToken);
- }
-
- result = scalarValue;
- break;
- case DbCommandMethod.ExecuteReader:
- var readerResult = logger == null
- ? null
- : await logger.CommandReaderExecutingAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- startTime: startTime,
- cancellationToken);
-
- var reader = readerResult.HasValue
- ? readerResult.Value.Result
- : await dbCommand.ExecuteReaderAsync(cancellationToken);
-
- if (logger != null)
- {
- reader = await logger.CommandReaderExecutedAsync(
- dbCommand,
- commandId,
- connection.ConnectionId,
- reader,
- startTime,
- stopwatch.Elapsed,
- cancellationToken);
- }
-
- readerOpen = true;
-
- result = new RelationalDataReader(
- connection,
- dbCommand,
- reader,
- commandId,
- logger);
-
- break;
- default:
- throw new NotSupportedException();
+ reader = await logger.CommandReaderExecutedAsync(
+ command,
+ context,
+ commandId,
+ connection.ConnectionId,
+ reader,
+ startTime,
+ stopwatch.Elapsed,
+ cancellationToken);
}
+
+ var result = new RelationalDataReader(
+ connection,
+ command,
+ reader,
+ commandId,
+ logger);
+
+ readerOpen = true;
+
+ return result;
}
catch (Exception exception)
{
logger?.CommandError(
- dbCommand,
- executeMethod,
+ command,
+ context,
+ DbCommandMethod.ExecuteReader,
commandId,
connection.ConnectionId,
exception,
@@ -454,19 +493,15 @@ protected virtual async Task ExecuteAsync(
{
if (!readerOpen)
{
- dbCommand.Parameters.Clear();
- dbCommand.Dispose();
- connection.Close();
+ CleanupCommand(command, connection);
}
}
-
- return result;
}
///
///
- /// Template method called by amd to
- /// create a for the given and configure
+ /// Template method called by the execute methods to
+ /// create a for the given and configure
/// timeouts and transactions.
///
///
@@ -479,8 +514,10 @@ protected virtual async Task ExecuteAsync(
/// The created command.
protected virtual DbCommand CreateCommand(
[NotNull] IRelationalConnection connection,
- [NotNull] IReadOnlyDictionary parameterValues)
+ [CanBeNull] IReadOnlyDictionary parameterValues)
{
+ Check.NotNull(connection, nameof(connection));
+
var command = connection.DbConnection.CreateCommand();
command.CommandText = CommandText;
@@ -495,7 +532,8 @@ protected virtual DbCommand CreateCommand(
command.CommandTimeout = (int)connection.CommandTimeout;
}
- if (Parameters.Count > 0)
+ if (Parameters != null
+ && Parameters.Count > 0)
{
if (parameterValues == null)
{
@@ -504,9 +542,9 @@ protected virtual DbCommand CreateCommand(
Parameters[0].InvariantName));
}
- foreach (var parameter in Parameters)
+ for (var i = 0; i < Parameters.Count; i++)
{
- parameter.AddDbParameter(command, parameterValues);
+ Parameters[i].AddDbParameter(command, parameterValues);
}
}
diff --git a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs
new file mode 100644
index 00000000000..ab4a049f524
--- /dev/null
+++ b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs
@@ -0,0 +1,69 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Utilities;
+
+namespace Microsoft.EntityFrameworkCore.Storage
+{
+ ///
+ ///
+ /// A parameter object for the execution methods on .
+ ///
+ ///
+ /// This type is typically used by database providers (and other extensions). It is generally
+ /// not used in application code.
+ ///
+ ///
+ public readonly struct RelationalCommandParameterObject
+ {
+ ///
+ ///
+ /// Creates a new parameter object for the given parameters.
+ ///
+ ///
+ /// This type is typically used by database providers (and other extensions). It is generally
+ /// not used in application code.
+ ///
+ ///
+ /// The connection on which the command will execute.
+ /// The SQL parameter values to use, or null if none.
+ /// The current instance, or null if it is not known.
+ /// A logger, or null if no logger is available.
+ public RelationalCommandParameterObject(
+ [NotNull] IRelationalConnection connection,
+ [CanBeNull] IReadOnlyDictionary parameterValues,
+ [CanBeNull] DbContext context,
+ [CanBeNull] IDiagnosticsLogger logger)
+ {
+ Check.NotNull(connection, nameof(connection));
+
+ Connection = connection;
+ ParameterValues = parameterValues;
+ Context = context;
+ Logger = logger;
+ }
+
+ ///
+ /// The connection on which the command will execute.
+ ///
+ public IRelationalConnection Connection { get; }
+
+ ///
+ /// The SQL parameter values to use, or null if none.
+ ///
+ public IReadOnlyDictionary ParameterValues { get; }
+
+ ///
+ /// The current instance, or null if it is not known.
+ ///
+ public DbContext Context { get; }
+
+ ///
+ /// A logger, or null if no logger is available.
+ ///
+ public IDiagnosticsLogger Logger { get; }
+ }
+}
diff --git a/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs b/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
index a3c7b0ad85e..b291768839d 100644
--- a/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
+++ b/src/EFCore.Relational/Storage/RelationalDatabaseCreatorDependencies.cs
@@ -62,6 +62,7 @@ public sealed class RelationalDatabaseCreatorDependencies
/// The to be used.
/// The to be used.
/// The to be used.
+ /// Contains the currently in use.
/// The command logger.
[EntityFrameworkInternal]
public RelationalDatabaseCreatorDependencies(
@@ -72,6 +73,7 @@ public RelationalDatabaseCreatorDependencies(
[NotNull] IMigrationCommandExecutor migrationCommandExecutor,
[NotNull] ISqlGenerationHelper sqlGenerationHelper,
[NotNull] IExecutionStrategyFactory executionStrategyFactory,
+ [NotNull] ICurrentDbContext currentDbContext,
[NotNull] IDiagnosticsLogger commandLogger)
{
Check.NotNull(model, nameof(model));
@@ -81,6 +83,7 @@ public RelationalDatabaseCreatorDependencies(
Check.NotNull(migrationCommandExecutor, nameof(migrationCommandExecutor));
Check.NotNull(sqlGenerationHelper, nameof(sqlGenerationHelper));
Check.NotNull(executionStrategyFactory, nameof(executionStrategyFactory));
+ Check.NotNull(currentDbContext, nameof(currentDbContext));
Check.NotNull(commandLogger, nameof(commandLogger));
Model = model;
@@ -90,6 +93,7 @@ public RelationalDatabaseCreatorDependencies(
MigrationCommandExecutor = migrationCommandExecutor;
SqlGenerationHelper = sqlGenerationHelper;
ExecutionStrategyFactory = executionStrategyFactory;
+ CurrentDbContext = currentDbContext;
CommandLogger = commandLogger;
}
@@ -133,6 +137,11 @@ public RelationalDatabaseCreatorDependencies(
///
public IDiagnosticsLogger CommandLogger { get; }
+ ///
+ /// Contains the currently in use.
+ ///
+ public ICurrentDbContext CurrentDbContext { get; }
+
///
/// Clones this dependency parameter object with one service replaced.
///
@@ -147,6 +156,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IModel model)
MigrationCommandExecutor,
SqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -163,6 +173,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IRelationalConnectio
MigrationCommandExecutor,
SqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -179,6 +190,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IMigrationsModelDiff
MigrationCommandExecutor,
SqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -195,6 +207,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IMigrationsSqlGenera
MigrationCommandExecutor,
SqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -211,6 +224,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IMigrationCommandExe
migrationCommandExecutor,
SqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -227,6 +241,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] ISqlGenerationHelper
MigrationCommandExecutor,
sqlGenerationHelper,
ExecutionStrategyFactory,
+ CurrentDbContext,
CommandLogger);
///
@@ -243,6 +258,24 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IExecutionStrategyFa
MigrationCommandExecutor,
SqlGenerationHelper,
executionStrategyFactory,
+ CurrentDbContext,
+ CommandLogger);
+
+ ///
+ /// Clones this dependency parameter object with one service replaced.
+ ///
+ /// A replacement for the current dependency of this type.
+ /// A new parameter object with the given service replaced.
+ public RelationalDatabaseCreatorDependencies With([NotNull] ICurrentDbContext currentDbContext)
+ => new RelationalDatabaseCreatorDependencies(
+ Model,
+ Connection,
+ ModelDiffer,
+ MigrationsSqlGenerator,
+ MigrationCommandExecutor,
+ SqlGenerationHelper,
+ ExecutionStrategyFactory,
+ currentDbContext,
CommandLogger);
///
@@ -259,6 +292,7 @@ public RelationalDatabaseCreatorDependencies With([NotNull] IDiagnosticsLogger The command builder factory.
/// The sql generator.
/// The update generator.
+ /// Contains the currently in use.
/// A logger.
public ModificationCommandBatchFactoryDependencies(
[NotNull] IRelationalCommandBuilderFactory commandBuilderFactory,
[NotNull] ISqlGenerationHelper sqlGenerationHelper,
[NotNull] IUpdateSqlGenerator updateSqlGenerator,
[NotNull] IRelationalValueBufferFactoryFactory valueBufferFactoryFactory,
+ [NotNull] ICurrentDbContext currentDbContext,
[NotNull] IDiagnosticsLogger logger)
{
Check.NotNull(commandBuilderFactory, nameof(commandBuilderFactory));
@@ -69,6 +72,7 @@ public ModificationCommandBatchFactoryDependencies(
SqlGenerationHelper = sqlGenerationHelper;
UpdateSqlGenerator = updateSqlGenerator;
ValueBufferFactoryFactory = valueBufferFactoryFactory;
+ CurrentDbContext = currentDbContext;
Logger = logger;
}
@@ -97,6 +101,11 @@ public ModificationCommandBatchFactoryDependencies(
///
public IRelationalValueBufferFactoryFactory ValueBufferFactoryFactory { get; }
+ ///
+ /// Contains the currently in use.
+ ///
+ public ICurrentDbContext CurrentDbContext { get; }
+
///
/// Clones this dependency parameter object with one service replaced.
///
@@ -108,6 +117,7 @@ public ModificationCommandBatchFactoryDependencies With([NotNull] IDiagnosticsLo
SqlGenerationHelper,
UpdateSqlGenerator,
ValueBufferFactoryFactory,
+ CurrentDbContext,
logger);
///
@@ -121,6 +131,7 @@ public ModificationCommandBatchFactoryDependencies With([NotNull] IRelationalVal
SqlGenerationHelper,
UpdateSqlGenerator,
valueBufferFactoryFactory,
+ CurrentDbContext,
Logger);
///
@@ -134,6 +145,7 @@ public ModificationCommandBatchFactoryDependencies With([NotNull] IRelationalCom
SqlGenerationHelper,
UpdateSqlGenerator,
ValueBufferFactoryFactory,
+ CurrentDbContext,
Logger);
///
@@ -147,6 +159,7 @@ public ModificationCommandBatchFactoryDependencies With([NotNull] ISqlGeneration
sqlGenerationHelper,
UpdateSqlGenerator,
ValueBufferFactoryFactory,
+ CurrentDbContext,
Logger);
///
@@ -160,6 +173,21 @@ public ModificationCommandBatchFactoryDependencies With([NotNull] IUpdateSqlGene
SqlGenerationHelper,
updateSqlGenerator,
ValueBufferFactoryFactory,
+ CurrentDbContext,
+ Logger);
+
+ ///
+ /// Clones this dependency parameter object with one service replaced.
+ ///
+ /// A replacement for the current dependency of this type.
+ /// A new parameter object with the given service replaced.
+ public ModificationCommandBatchFactoryDependencies With([NotNull] ICurrentDbContext currentDbContext)
+ => new ModificationCommandBatchFactoryDependencies(
+ CommandBuilderFactory,
+ SqlGenerationHelper,
+ UpdateSqlGenerator,
+ ValueBufferFactoryFactory,
+ currentDbContext,
Logger);
}
}
diff --git a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs
index 1c3860c4819..b25bd61e543 100644
--- a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs
+++ b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs
@@ -25,8 +25,6 @@ namespace Microsoft.EntityFrameworkCore.Update
///
public abstract class ReaderModificationCommandBatch : ModificationCommandBatch
{
- private readonly IRelationalCommandBuilderFactory _commandBuilderFactory;
- private readonly IRelationalValueBufferFactoryFactory _valueBufferFactoryFactory;
private readonly List _modificationCommands = new List();
///
@@ -37,37 +35,28 @@ protected ReaderModificationCommandBatch([NotNull] ModificationCommandBatchFacto
{
Check.NotNull(dependencies, nameof(dependencies));
- _commandBuilderFactory = dependencies.CommandBuilderFactory;
- SqlGenerationHelper = dependencies.SqlGenerationHelper;
- UpdateSqlGenerator = dependencies.UpdateSqlGenerator;
- _valueBufferFactoryFactory = dependencies.ValueBufferFactoryFactory;
- Logger = dependencies.Logger;
+ Dependencies = dependencies;
}
///
- /// Gets or sets the cached command text for the commands in the batch.
+ /// Service dependencies.
///
- protected virtual StringBuilder CachedCommandText { get; [param: NotNull] set; }
+ public virtual ModificationCommandBatchFactoryDependencies Dependencies { get; }
///
- /// The ordinal of the last command for which command text was built.
+ /// The update SQL generator.
///
- protected virtual int LastCachedCommandIndex { get; set; }
+ protected virtual IUpdateSqlGenerator UpdateSqlGenerator => Dependencies.UpdateSqlGenerator;
///
- /// A helper for SQL generation.
- ///
- protected virtual ISqlGenerationHelper SqlGenerationHelper { get; }
-
- ///
- /// A SQL generator for insert, update, and delete commands.
+ /// Gets or sets the cached command text for the commands in the batch.
///
- protected virtual IUpdateSqlGenerator UpdateSqlGenerator { get; }
+ protected virtual StringBuilder CachedCommandText { get; [param: NotNull] set; }
///
- /// A logger.
+ /// The ordinal of the last command for which command text was built.
///
- protected virtual IDiagnosticsLogger Logger { get; }
+ protected virtual int LastCachedCommandIndex { get; set; }
///
/// The list of conceptual insert/update/delete s in the batch.
@@ -194,7 +183,7 @@ protected virtual int GetParameterCount()
/// The command.
protected virtual RawSqlCommand CreateStoreCommand()
{
- var commandBuilder = _commandBuilderFactory
+ var commandBuilder = Dependencies.CommandBuilderFactory
.Create()
.Append(GetCommandText());
@@ -212,7 +201,7 @@ protected virtual RawSqlCommand CreateStoreCommand()
{
commandBuilder.AddParameter(
columnModification.ParameterName,
- SqlGenerationHelper.GenerateParameterName(columnModification.ParameterName),
+ Dependencies.SqlGenerationHelper.GenerateParameterName(columnModification.ParameterName),
columnModification.Property);
parameterValues.Add(columnModification.ParameterName, columnModification.Value);
@@ -222,7 +211,7 @@ protected virtual RawSqlCommand CreateStoreCommand()
{
commandBuilder.AddParameter(
columnModification.OriginalParameterName,
- SqlGenerationHelper.GenerateParameterName(columnModification.OriginalParameterName),
+ Dependencies.SqlGenerationHelper.GenerateParameterName(columnModification.OriginalParameterName),
columnModification.Property);
parameterValues.Add(columnModification.OriginalParameterName, columnModification.OriginalValue);
@@ -247,9 +236,11 @@ public override void Execute(IRelationalConnection connection)
try
{
using (var dataReader = storeCommand.RelationalCommand.ExecuteReader(
- connection,
- storeCommand.ParameterValues,
- Logger))
+ new RelationalCommandParameterObject(
+ connection,
+ storeCommand.ParameterValues,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.Logger)))
{
Consume(dataReader);
}
@@ -282,9 +273,11 @@ public override async Task ExecuteAsync(
try
{
using (var dataReader = await storeCommand.RelationalCommand.ExecuteReaderAsync(
- connection,
- storeCommand.ParameterValues,
- Logger,
+ new RelationalCommandParameterObject(
+ connection,
+ storeCommand.ParameterValues,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.Logger),
cancellationToken))
{
await ConsumeAsync(dataReader, cancellationToken);
@@ -326,7 +319,7 @@ protected abstract Task ConsumeAsync(
///
/// The factory.
protected virtual IRelationalValueBufferFactory CreateValueBufferFactory([NotNull] IReadOnlyList columnModifications)
- => _valueBufferFactoryFactory
+ => Dependencies.ValueBufferFactoryFactory
.Create(
Check.NotNull(columnModifications, nameof(columnModifications))
.Where(c => c.IsRead)
diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
index 557aae7da40..41ecf151122 100644
--- a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
+++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
@@ -118,9 +118,11 @@ public override bool HasTables()
_connection,
connection => (int)CreateHasTablesCommand()
.ExecuteScalar(
- connection,
- null,
- Dependencies.CommandLogger) != 0);
+ new RelationalCommandParameterObject(
+ connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger)) != 0);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -133,9 +135,11 @@ public override Task HasTablesAsync(CancellationToken cancellationToken =
_connection,
async (connection, ct) => (int)await CreateHasTablesCommand()
.ExecuteScalarAsync(
- connection,
- null,
- Dependencies.CommandLogger,
+ new RelationalCommandParameterObject(
+ connection,
+ null,
+ Dependencies.CurrentDbContext.Context,
+ Dependencies.CommandLogger),
cancellationToken: ct) != 0, cancellationToken);
private IRelationalCommand CreateHasTablesCommand()
diff --git a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs
index 761e0bdcafb..4e7030c4626 100644
--- a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs
+++ b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs
@@ -60,7 +60,12 @@ protected override long GetNewLowValue()
=> (long)Convert.ChangeType(
_rawSqlCommandBuilder
.Build(_sqlGenerator.GenerateNextSequenceValueOperation(_sequence.Name, _sequence.Schema))
- .ExecuteScalar(_connection, null, _commandLogger),
+ .ExecuteScalar(
+ new RelationalCommandParameterObject(
+ _connection,
+ null,
+ null,
+ _commandLogger)),
typeof(long),
CultureInfo.InvariantCulture);
@@ -74,7 +79,13 @@ protected override async Task GetNewLowValueAsync(CancellationToken cancel
=> (long)Convert.ChangeType(
await _rawSqlCommandBuilder
.Build(_sqlGenerator.GenerateNextSequenceValueOperation(_sequence.Name, _sequence.Schema))
- .ExecuteScalarAsync(_connection, null, _commandLogger, cancellationToken: cancellationToken),
+ .ExecuteScalarAsync(
+ new RelationalCommandParameterObject(
+ _connection,
+ null,
+ null,
+ _commandLogger),
+ cancellationToken),
typeof(long),
CultureInfo.InvariantCulture);
diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs
index e5869db01a5..1ffcd9ddc94 100644
--- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs
+++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs
@@ -58,7 +58,12 @@ public override void Create()
Dependencies.Connection.Open();
_rawSqlCommandBuilder.Build("PRAGMA journal_mode = 'wal';")
- .ExecuteNonQuery(Dependencies.Connection, null, Dependencies.CommandLogger);
+ .ExecuteNonQuery(
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ null,
+ Dependencies.CommandLogger));
Dependencies.Connection.Close();
}
@@ -96,7 +101,12 @@ public override bool HasTables()
{
var count = (long)_rawSqlCommandBuilder
.Build("SELECT COUNT(*) FROM \"sqlite_master\" WHERE \"type\" = 'table' AND \"rootpage\" IS NOT NULL;")
- .ExecuteScalar(Dependencies.Connection, null, Dependencies.CommandLogger);
+ .ExecuteScalar(
+ new RelationalCommandParameterObject(
+ Dependencies.Connection,
+ null,
+ null,
+ Dependencies.CommandLogger));
return count != 0;
}
diff --git a/src/EFCore/DbContext.cs b/src/EFCore/DbContext.cs
index c8e31f5de37..33940692e4a 100644
--- a/src/EFCore/DbContext.cs
+++ b/src/EFCore/DbContext.cs
@@ -118,7 +118,7 @@ public virtual DatabaseFacade Database
{
CheckDisposed();
- return _database ?? (_database = new DatabaseFacade(this));
+ return _database ??= new DatabaseFacade(this);
}
}
@@ -126,8 +126,7 @@ public virtual DatabaseFacade Database
/// Provides access to information and operations for entity instances this context is tracking.
///
public virtual ChangeTracker ChangeTracker
- => _changeTracker
- ?? (_changeTracker = InternalServiceProvider.GetRequiredService().Create());
+ => _changeTracker ??= InternalServiceProvider.GetRequiredService().Create();
///
/// The metadata about the shape of entities, the relationships between them, and how they map to the database.
@@ -336,7 +335,7 @@ private IDbContextDependencies DbContextDependencies
{
CheckDisposed();
- return _dbContextDependencies ?? (_dbContextDependencies = InternalServiceProvider.GetRequiredService());
+ return _dbContextDependencies ??= InternalServiceProvider.GetRequiredService();
}
}
diff --git a/src/EFCore/Diagnostics/DbContextEventData.cs b/src/EFCore/Diagnostics/DbContextEventData.cs
index 7d122f7b579..4bc779ff9b7 100644
--- a/src/EFCore/Diagnostics/DbContextEventData.cs
+++ b/src/EFCore/Diagnostics/DbContextEventData.cs
@@ -18,11 +18,11 @@ public class DbContextEventData : EventData
///
/// The event definition.
/// A delegate that generates a log message for this event.
- /// The current .
+ /// The current , or null if not known.
public DbContextEventData(
[NotNull] EventDefinitionBase eventDefinition,
[NotNull] Func messageGenerator,
- [NotNull] DbContext context)
+ [CanBeNull] DbContext context)
: base(eventDefinition, messageGenerator)
{
Context = context;
diff --git a/src/EFCore/Extensions/TransactionsDatabaseFacadeExtensions.cs b/src/EFCore/Extensions/TransactionsDatabaseFacadeExtensions.cs
index 380c7a0cfb0..021c147c1e5 100644
--- a/src/EFCore/Extensions/TransactionsDatabaseFacadeExtensions.cs
+++ b/src/EFCore/Extensions/TransactionsDatabaseFacadeExtensions.cs
@@ -5,6 +5,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -25,7 +26,7 @@ public static class TransactionsDatabaseFacadeExtensions
public static void EnlistTransaction([NotNull] this DatabaseFacade databaseFacade, [CanBeNull] Transaction transaction)
{
Check.NotNull(databaseFacade, nameof(databaseFacade));
- if (databaseFacade.GetService() is ITransactionEnlistmentManager transactionManager)
+ if (((IDatabaseFacadeDependenciesAccessor)databaseFacade).Dependencies.TransactionManager is ITransactionEnlistmentManager transactionManager)
{
transactionManager.EnlistTransaction(transaction);
}
@@ -43,7 +44,7 @@ public static void EnlistTransaction([NotNull] this DatabaseFacade databaseFacad
public static Transaction GetEnlistedTransaction([NotNull] this DatabaseFacade databaseFacade)
{
Check.NotNull(databaseFacade, nameof(databaseFacade));
- if (databaseFacade.GetService() is ITransactionEnlistmentManager transactionManager)
+ if (((IDatabaseFacadeDependenciesAccessor)databaseFacade).Dependencies.TransactionManager is ITransactionEnlistmentManager transactionManager)
{
return transactionManager.EnlistedTransaction;
}
diff --git a/src/EFCore/Infrastructure/DatabaseFacade.cs b/src/EFCore/Infrastructure/DatabaseFacade.cs
index bcdbe4d7156..4c08d88552e 100644
--- a/src/EFCore/Infrastructure/DatabaseFacade.cs
+++ b/src/EFCore/Infrastructure/DatabaseFacade.cs
@@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -18,12 +19,10 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure
/// Instances of this class are typically obtained from and it is not designed
/// to be directly constructed in your application code.
///
- public class DatabaseFacade : IInfrastructure
+ public class DatabaseFacade : IInfrastructure, IDatabaseFacadeDependenciesAccessor
{
private readonly DbContext _context;
- private IDatabaseCreator _databaseCreator;
- private IDbContextTransactionManager _transactionManager;
- private IExecutionStrategyFactory _executionStrategyFactory;
+ private IDatabaseFacadeDependencies _dependencies;
///
/// Initializes a new instance of the class. Instances of this class are typically
@@ -38,6 +37,9 @@ public DatabaseFacade([NotNull] DbContext context)
_context = context;
}
+ private IDatabaseFacadeDependencies Dependencies
+ => _dependencies ??= _context.GetService();
+
///
///
/// Ensures that the database for the context exists. If it exists, no action is taken. If it does not
@@ -52,7 +54,7 @@ public DatabaseFacade([NotNull] DbContext context)
///
///
/// True if the database is created, false if it already existed.
- public virtual bool EnsureCreated() => DatabaseCreator.EnsureCreated();
+ public virtual bool EnsureCreated() => Dependencies.DatabaseCreator.EnsureCreated();
///
///
@@ -73,7 +75,7 @@ public DatabaseFacade([NotNull] DbContext context)
/// false if it already existed.
///
public virtual Task EnsureCreatedAsync(CancellationToken cancellationToken = default)
- => DatabaseCreator.EnsureCreatedAsync(cancellationToken);
+ => Dependencies.DatabaseCreator.EnsureCreatedAsync(cancellationToken);
///
///
@@ -86,7 +88,7 @@ public virtual Task EnsureCreatedAsync(CancellationToken cancellationToken
///
///
/// True if the database is deleted, false if it did not exist.
- public virtual bool EnsureDeleted() => DatabaseCreator.EnsureDeleted();
+ public virtual bool EnsureDeleted() => Dependencies.DatabaseCreator.EnsureDeleted();
///
///
@@ -104,7 +106,7 @@ public virtual Task EnsureCreatedAsync(CancellationToken cancellationToken
/// false if it did not exist.
///
public virtual Task EnsureDeletedAsync(CancellationToken cancellationToken = default)
- => DatabaseCreator.EnsureDeletedAsync(cancellationToken);
+ => Dependencies.DatabaseCreator.EnsureDeletedAsync(cancellationToken);
///
///
@@ -117,7 +119,7 @@ public virtual Task EnsureDeletedAsync(CancellationToken cancellationToken
///
/// True if the database is available; false otherwise.
public virtual bool CanConnect()
- => DatabaseCreator.CanConnect();
+ => Dependencies.DatabaseCreator.CanConnect();
///
///
@@ -131,7 +133,7 @@ public virtual bool CanConnect()
/// A to observe while waiting for the task to complete.
/// True if the database is available; false otherwise.
public virtual Task CanConnectAsync(CancellationToken cancellationToken = default)
- => DatabaseCreator.CanConnectAsync(cancellationToken);
+ => Dependencies.DatabaseCreator.CanConnectAsync(cancellationToken);
///
/// Starts a new transaction.
@@ -140,7 +142,7 @@ public virtual Task CanConnectAsync(CancellationToken cancellationToken =
/// A that represents the started transaction.
///
public virtual IDbContextTransaction BeginTransaction()
- => TransactionManager.BeginTransaction();
+ => Dependencies.TransactionManager.BeginTransaction();
///
/// Asynchronously starts a new transaction.
@@ -151,26 +153,26 @@ public virtual IDbContextTransaction BeginTransaction()
/// that represents the started transaction.
///
public virtual Task BeginTransactionAsync(CancellationToken cancellationToken = default)
- => TransactionManager.BeginTransactionAsync(cancellationToken);
+ => Dependencies.TransactionManager.BeginTransactionAsync(cancellationToken);
///
/// Applies the outstanding operations in the current transaction to the database.
///
public virtual void CommitTransaction()
- => TransactionManager.CommitTransaction();
+ => Dependencies.TransactionManager.CommitTransaction();
///
/// Discards the outstanding operations in the current transaction.
///
public virtual void RollbackTransaction()
- => TransactionManager.RollbackTransaction();
+ => Dependencies.TransactionManager.RollbackTransaction();
///
/// Creates an instance of the configured .
///
/// An instance.
public virtual IExecutionStrategy CreateExecutionStrategy()
- => ExecutionStrategyFactory.Create();
+ => Dependencies.ExecutionStrategyFactory.Create();
///
///
@@ -189,7 +191,7 @@ public virtual IExecutionStrategy CreateExecutionStrategy()
///
///
public virtual IDbContextTransaction CurrentTransaction
- => TransactionManager.CurrentTransaction;
+ => Dependencies.TransactionManager.CurrentTransaction;
///
///
@@ -227,6 +229,7 @@ public virtual IDbContextTransaction CurrentTransaction
///
///
public virtual string ProviderName
+ // Needs to be lazy because used from OnModelCreating
=> _context.GetService>()
?.Select(p => p.Name)
.FirstOrDefault();
@@ -242,14 +245,23 @@ public virtual string ProviderName
///
IServiceProvider IInfrastructure.Instance => ((IInfrastructure)_context).Instance;
- private IDbContextTransactionManager TransactionManager
- => _transactionManager ?? (_transactionManager = this.GetService());
-
- private IDatabaseCreator DatabaseCreator
- => _databaseCreator ?? (_databaseCreator = this.GetService());
+ ///
+ /// 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.
+ ///
+ IDatabaseFacadeDependencies IDatabaseFacadeDependenciesAccessor.Dependencies
+ => Dependencies;
- private IExecutionStrategyFactory ExecutionStrategyFactory
- => _executionStrategyFactory ?? (_executionStrategyFactory = this.GetService());
+ ///
+ /// 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.
+ ///
+ DbContext IDatabaseFacadeDependenciesAccessor.Context
+ => _context;
#region Hidden System.Object members
diff --git a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs
index e2cbcf94b12..3743a7eea50 100644
--- a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs
+++ b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs
@@ -118,6 +118,7 @@ public static readonly IDictionary CoreServices
{ typeof(IUpdateAdapterFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(ICurrentDbContext), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IDbContextDependencies), new ServiceCharacteristics(ServiceLifetime.Scoped) },
+ { typeof(IDatabaseFacadeDependencies), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IDbContextOptions), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IDatabase), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IDatabaseCreator), new ServiceCharacteristics(ServiceLifetime.Scoped) },
@@ -228,6 +229,7 @@ public virtual EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd();
TryAdd();
TryAdd();
+ TryAdd();
TryAdd();
TryAdd();
TryAdd();
diff --git a/src/EFCore/Internal/DatabaseFacadeDependencies.cs b/src/EFCore/Internal/DatabaseFacadeDependencies.cs
new file mode 100644
index 00000000000..15752f6993f
--- /dev/null
+++ b/src/EFCore/Internal/DatabaseFacadeDependencies.cs
@@ -0,0 +1,106 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.EntityFrameworkCore.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.
+ ///
+ ///
+ /// The service lifetime is . This means that each
+ /// instance will use its own instance of this service.
+ /// The implementation may depend on other services registered with any lifetime.
+ /// The implementation does not need to be thread-safe.
+ ///
+ ///
+ public class DatabaseFacadeDependencies : IDatabaseFacadeDependencies
+ {
+ ///
+ /// 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 DatabaseFacadeDependencies(
+ [NotNull] IDbContextTransactionManager transactionManager,
+ [NotNull] IDatabaseCreator databaseCreator,
+ [NotNull] IExecutionStrategyFactory executionStrategyFactory,
+ [NotNull] IEnumerable databaseProviders,
+ [NotNull] IDiagnosticsLogger commandLogger,
+ [NotNull] IConcurrencyDetector concurrencyDetector)
+ {
+ TransactionManager = transactionManager;
+ DatabaseCreator = databaseCreator;
+ ExecutionStrategyFactory = executionStrategyFactory;
+ DatabaseProviders = databaseProviders;
+ CommandLogger = commandLogger;
+ ConcurrencyDetector = concurrencyDetector;
+ }
+
+ ///
+ /// 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 IDbContextTransactionManager TransactionManager { 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 virtual IDatabaseCreator DatabaseCreator { 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 virtual IExecutionStrategyFactory ExecutionStrategyFactory { 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 virtual IEnumerable DatabaseProviders { 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 virtual IDiagnosticsLogger CommandLogger { 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 virtual IConcurrencyDetector ConcurrencyDetector { 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 virtual DbContext Context => null;
+ }
+}
diff --git a/src/EFCore/Internal/DbContextDependencies.cs b/src/EFCore/Internal/DbContextDependencies.cs
index 9ff5a8dbf7d..a0c38aad5a6 100644
--- a/src/EFCore/Internal/DbContextDependencies.cs
+++ b/src/EFCore/Internal/DbContextDependencies.cs
@@ -16,12 +16,14 @@ namespace Microsoft.EntityFrameworkCore.Internal
/// Service dependencies parameter class for
///
///
- /// This type supports the Entity Framework Core infrastructure and is not intended to be used
- /// directly from your code. This type may change or be removed in future releases.
+ /// 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.
///
///
- /// The service lifetime is . This means that each
- /// instance will use its own instance of this service.
+ /// The service lifetime is . This means that each
+ /// instance will use its own instance of this service.
/// The implementation may depend on other services registered with any lifetime.
/// The implementation does not need to be thread-safe.
///
diff --git a/src/EFCore/Internal/IDatabaseFacadeDependencies.cs b/src/EFCore/Internal/IDatabaseFacadeDependencies.cs
new file mode 100644
index 00000000000..9be015a2694
--- /dev/null
+++ b/src/EFCore/Internal/IDatabaseFacadeDependencies.cs
@@ -0,0 +1,76 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.EntityFrameworkCore.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.
+ ///
+ ///
+ /// The service lifetime is . This means that each
+ /// instance will use its own instance of this service.
+ /// The implementation may depend on other services registered with any lifetime.
+ /// The implementation does not need to be thread-safe.
+ ///
+ ///
+ // This is used by Relational, but is still internal since it's only for an optimization; no provider needs access.
+ public interface IDatabaseFacadeDependencies
+ {
+ ///
+ /// 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.
+ ///
+ IDbContextTransactionManager TransactionManager { 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.
+ ///
+ IDatabaseCreator DatabaseCreator { 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.
+ ///
+ IExecutionStrategyFactory ExecutionStrategyFactory { 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.
+ ///
+ IEnumerable DatabaseProviders { 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.
+ ///
+ IDiagnosticsLogger CommandLogger { 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.
+ ///
+ IConcurrencyDetector ConcurrencyDetector { get; }
+ }
+}
diff --git a/src/EFCore/Internal/IDatabaseFacadeDependenciesAccessor.cs b/src/EFCore/Internal/IDatabaseFacadeDependenciesAccessor.cs
new file mode 100644
index 00000000000..7c4d0a4a5b4
--- /dev/null
+++ b/src/EFCore/Internal/IDatabaseFacadeDependenciesAccessor.cs
@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.EntityFrameworkCore.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.
+ ///
+ // This is used by Relational, but is still internal since it's only for an optimization; no provider needs access.
+ public interface IDatabaseFacadeDependenciesAccessor
+ {
+ ///
+ /// 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.
+ ///
+ IDatabaseFacadeDependencies Dependencies { 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.
+ ///
+ DbContext Context { get; }
+ }
+}
diff --git a/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs b/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs
index 5550be88a63..4a5a89dcddf 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs
@@ -107,6 +107,7 @@ var migrationAssembly
services.GetRequiredService(),
services.GetRequiredService(),
services.GetRequiredService(),
+ services.GetRequiredService(),
services.GetRequiredService>(),
services.GetRequiredService>(),
services.GetRequiredService())));
diff --git a/test/EFCore.Relational.Specification.Tests/InterceptionTestBase.cs b/test/EFCore.Relational.Specification.Tests/InterceptionTestBase.cs
index bca0f7ab266..3d4e3728913 100644
--- a/test/EFCore.Relational.Specification.Tests/InterceptionTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/InterceptionTestBase.cs
@@ -60,6 +60,7 @@ public virtual async Task Intercept_query_passively(bool async, bool inj
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
}
return interceptor.CommandText;
@@ -91,18 +92,26 @@ public virtual async Task Intercept_scalar_passively(bool async, bool inject)
if (async)
{
- Assert.Equal(1, Convert.ToInt32(await command.ExecuteScalarAsync(connection, null, logger)));
+ Assert.Equal(
+ 1, Convert.ToInt32(
+ await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(
+ connection, null, context, logger))));
Assert.True(interceptor.AsyncCalled);
}
else
{
- Assert.Equal(1, Convert.ToInt32(command.ExecuteScalar(connection, null, logger)));
+ Assert.Equal(
+ 1, Convert.ToInt32(
+ command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, null, context, logger))));
Assert.True(interceptor.SyncCalled);
}
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(sql, interceptor.CommandText);
}
@@ -144,6 +153,7 @@ public virtual async Task Intercept_non_query_passively(bool async, bool inject)
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(nonQuery, interceptor.CommandText);
}
@@ -192,6 +202,7 @@ public virtual async Task Intercept_query_to_suppress_execution(bool asy
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
}
return interceptor.CommandText;
@@ -246,7 +257,9 @@ public virtual async Task Intercept_scalar_to_suppress_execution(bool async, boo
{
Assert.Equal(
SuppressingScalarCommandInterceptor.InterceptedResult,
- await command.ExecuteScalarAsync(connection, null, logger));
+ await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(
+ connection, null, context, logger)));
Assert.True(interceptor.AsyncCalled);
}
@@ -254,7 +267,9 @@ public virtual async Task Intercept_scalar_to_suppress_execution(bool async, boo
{
Assert.Equal(
SuppressingScalarCommandInterceptor.InterceptedResult,
- command.ExecuteScalar(connection, null, logger));
+ command.ExecuteScalar(
+ new RelationalCommandParameterObject(
+ connection, null, context, logger)));
Assert.True(interceptor.SyncCalled);
}
@@ -262,6 +277,7 @@ public virtual async Task Intercept_scalar_to_suppress_execution(bool async, boo
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(sql, interceptor.CommandText);
}
@@ -327,6 +343,7 @@ public virtual async Task Intercept_non_query_to_suppress_execution(bool async,
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(nonQuery, interceptor.CommandText);
}
@@ -394,6 +411,7 @@ public virtual async Task Intercept_query_to_mutate_command(bool async,
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
}
return interceptor.CommandText;
@@ -449,18 +467,24 @@ public virtual async Task Intercept_scalar_to_mutate_command(bool async, bool in
if (async)
{
- Assert.Equal(2, Convert.ToInt32(await command.ExecuteScalarAsync(connection, null, logger)));
+ Assert.Equal(2, Convert.ToInt32(await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, null, context, logger))));
Assert.True(interceptor.AsyncCalled);
}
else
{
- Assert.Equal(2, Convert.ToInt32(command.ExecuteScalar(connection, null, logger)));
+ Assert.Equal(
+ 2, Convert.ToInt32(
+ command.ExecuteScalar(
+ new RelationalCommandParameterObject(
+ connection, null, context, logger))));
Assert.True(interceptor.SyncCalled);
}
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(MutatingScalarCommandInterceptor.MutatedSql, interceptor.CommandText);
}
@@ -525,6 +549,7 @@ public virtual async Task Intercept_non_query_to_mutate_command(bool async, bool
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(MutatingNonQueryCommandInterceptor.MutatedSql, interceptor.CommandText);
}
@@ -594,6 +619,7 @@ public virtual async Task Intercept_query_to_replace_execution(bool asyn
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
}
return interceptor.CommandText;
@@ -656,18 +682,23 @@ public virtual async Task Intercept_scalar_to_replace_execution(bool async, bool
if (async)
{
- Assert.Equal(2, Convert.ToInt32(await command.ExecuteScalarAsync(connection, null, logger)));
+ Assert.Equal(2, Convert.ToInt32(await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, null, context, logger))));
Assert.True(interceptor.AsyncCalled);
}
else
{
- Assert.Equal(2, Convert.ToInt32(command.ExecuteScalar(connection, null, logger)));
+ Assert.Equal(
+ 2, Convert.ToInt32(
+ command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, null, context, logger))));
Assert.True(interceptor.SyncCalled);
}
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(sql, interceptor.CommandText);
}
@@ -740,6 +771,7 @@ public virtual async Task Intercept_non_query_to_replace_execution(bool async, b
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(nonQuery, interceptor.CommandText);
}
@@ -824,6 +856,7 @@ public virtual async Task Intercept_query_to_replace_result(bool async,
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
}
return interceptor.CommandText;
@@ -931,7 +964,8 @@ public virtual async Task Intercept_scalar_to_replace_result(bool async, bool in
{
Assert.Equal(
ResultReplacingScalarCommandInterceptor.InterceptedResult,
- await command.ExecuteScalarAsync(connection, null, logger));
+ await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, null, context, logger)));
Assert.True(interceptor.AsyncCalled);
}
@@ -939,7 +973,8 @@ public virtual async Task Intercept_scalar_to_replace_result(bool async, bool in
{
Assert.Equal(
ResultReplacingScalarCommandInterceptor.InterceptedResult,
- command.ExecuteScalar(connection, null, logger));
+ command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, null, context, logger)));
Assert.True(interceptor.SyncCalled);
}
@@ -947,6 +982,7 @@ public virtual async Task Intercept_scalar_to_replace_result(bool async, bool in
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(sql, interceptor.CommandText);
}
@@ -1011,6 +1047,7 @@ public virtual async Task Intercept_non_query_to_replaceresult(bool async, bool
Assert.NotEqual(interceptor.AsyncCalled, interceptor.SyncCalled);
Assert.True(interceptor.ExecutingCalled);
Assert.True(interceptor.ExecutedCalled);
+ Assert.Same(context, interceptor.Context);
AssertSql(nonQuery, interceptor.CommandText);
}
@@ -1077,8 +1114,10 @@ public virtual async Task Intercept_scalar_to_throw(bool async, bool inject)
var logger = context.GetService>();
var exception = async
- ? await Assert.ThrowsAsync(() => command.ExecuteScalarAsync(connection, null, logger))
- : Assert.Throws(() => command.ExecuteScalar(connection, null, logger));
+ ? await Assert.ThrowsAsync(() => command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, null, context, logger)))
+ : Assert.Throws(() => command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, null, context, logger)));
Assert.Equal("Bang!", exception.Message);
}
@@ -1205,6 +1244,8 @@ private static async Task TestCompoisteQueryInterceptors(
Assert.True(interceptor2.ExecutingCalled);
Assert.True(interceptor1.ExecutedCalled);
Assert.True(interceptor2.ExecutedCalled);
+ Assert.Same(context, interceptor1.Context);
+ Assert.Same(context, interceptor2.Context);
}
[ConditionalTheory]
@@ -1229,8 +1270,10 @@ private static async Task TestCompositeScalarInterceptors(UniverseContext contex
Assert.Equal(
ResultReplacingScalarCommandInterceptor.InterceptedResult,
async
- ? await command.ExecuteScalarAsync(connection, null, logger)
- : command.ExecuteScalar(connection, null, logger));
+ ? await command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, null, context, logger))
+ : command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, null, context, logger)));
}
[ConditionalTheory]
@@ -1436,6 +1479,7 @@ protected CommandInterceptorBase(DbCommandMethod commandMethod)
_commandMethod = commandMethod;
}
+ public DbContext Context { get; set; }
public string CommandText { get; set; }
public Guid CommandId { get; set; }
public Guid ConnectionId { get; set; }
@@ -1596,10 +1640,12 @@ public virtual Task NonQueryExecutedAsync(
protected virtual void AssertExecuting(DbCommand command, CommandEventData eventData)
{
+ Assert.NotNull(eventData.Context);
Assert.NotEqual(default, eventData.CommandId);
Assert.NotEqual(default, eventData.ConnectionId);
Assert.Equal(_commandMethod, eventData.ExecuteMethod);
+ Context = eventData.Context;
CommandText = command.CommandText;
CommandId = eventData.CommandId;
ConnectionId = eventData.ConnectionId;
@@ -1608,6 +1654,7 @@ protected virtual void AssertExecuting(DbCommand command, CommandEventData event
protected virtual void AssertExecuted(DbCommand command, CommandExecutedEventData eventData)
{
+ Assert.Same(Context, eventData.Context);
Assert.Equal(CommandText, command.CommandText);
Assert.Equal(CommandId, eventData.CommandId);
Assert.Equal(ConnectionId, eventData.ConnectionId);
diff --git a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs
index b5e743cd733..54c44f58a77 100644
--- a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs
+++ b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs
@@ -40,7 +40,6 @@ public virtual void Clean(DatabaseFacade facade)
var connection = facade.GetService();
var sqlBuilder = facade.GetService();
var loggerFactory = facade.GetService();
- var commandLogger = facade.GetService>();
if (!creator.Exists())
{
@@ -84,7 +83,9 @@ public virtual void Clean(DatabaseFacade facade)
var customSql = BuildCustomSql(databaseModel);
if (!string.IsNullOrWhiteSpace(customSql))
{
- sqlBuilder.Build(customSql).ExecuteNonQuery(connection, null, null);
+ sqlBuilder.Build(customSql).ExecuteNonQuery(
+ new RelationalCommandParameterObject(
+ connection,null, null,null));
}
if (operations.Count > 0)
@@ -96,7 +97,8 @@ public virtual void Clean(DatabaseFacade facade)
customSql = BuildCustomEndingSql(databaseModel);
if (!string.IsNullOrWhiteSpace(customSql))
{
- sqlBuilder.Build(customSql).ExecuteNonQuery(connection, null, null);
+ sqlBuilder.Build(customSql).ExecuteNonQuery(
+ new RelationalCommandParameterObject(connection, null, null, null));
}
}
finally
diff --git a/test/EFCore.Relational.Tests/Migrations/MigrationCommandExecutorTest.cs b/test/EFCore.Relational.Tests/Migrations/MigrationCommandExecutorTest.cs
index 8d7526fcb18..cdbe606eb35 100644
--- a/test/EFCore.Relational.Tests/Migrations/MigrationCommandExecutorTest.cs
+++ b/test/EFCore.Relational.Tests/Migrations/MigrationCommandExecutorTest.cs
@@ -25,8 +25,8 @@ public async Task Executes_migtration_commands_in_same_transaction(bool async)
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(), logger),
- new MigrationCommand(CreateRelationalCommand(), logger)
+ new MigrationCommand(CreateRelationalCommand(), null, logger),
+ new MigrationCommand(CreateRelationalCommand(), null, logger)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
@@ -67,8 +67,8 @@ public async Task Executes_migration_commands_with_transaction_suppressed_outsid
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(), logger, transactionSuppressed: true),
- new MigrationCommand(CreateRelationalCommand(), logger, transactionSuppressed: true)
+ new MigrationCommand(CreateRelationalCommand(), null, logger, transactionSuppressed: true),
+ new MigrationCommand(CreateRelationalCommand(), null, logger, transactionSuppressed: true)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
@@ -103,8 +103,8 @@ public async Task Ends_transaction_when_transaction_is_suppressed(bool async)
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(), logger),
- new MigrationCommand(CreateRelationalCommand(), logger, transactionSuppressed: true)
+ new MigrationCommand(CreateRelationalCommand(), null, logger),
+ new MigrationCommand(CreateRelationalCommand(), null, logger, transactionSuppressed: true)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
@@ -144,8 +144,8 @@ public async Task Begins_new_transaction_when_transaction_nolonger_suppressed(bo
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(), logger, transactionSuppressed: true),
- new MigrationCommand(CreateRelationalCommand(), logger)
+ new MigrationCommand(CreateRelationalCommand(), null, logger, transactionSuppressed: true),
+ new MigrationCommand(CreateRelationalCommand(), null, logger)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
@@ -185,9 +185,9 @@ public async Task Executes_commands_in_order_regardless_of_transaction_suppressi
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(commandText: "First"), logger),
- new MigrationCommand(CreateRelationalCommand(commandText: "Second"), logger, transactionSuppressed: true),
- new MigrationCommand(CreateRelationalCommand(commandText: "Third"), logger)
+ new MigrationCommand(CreateRelationalCommand(commandText: "First"), null, logger),
+ new MigrationCommand(CreateRelationalCommand(commandText: "Second"), null, logger, transactionSuppressed: true),
+ new MigrationCommand(CreateRelationalCommand(commandText: "Third"), null, logger)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
@@ -260,7 +260,7 @@ public async Task Disposes_transaction_on_exception(bool async)
var commandList = new List
{
- new MigrationCommand(CreateRelationalCommand(), logger)
+ new MigrationCommand(CreateRelationalCommand(), null, logger)
};
var migrationCommandExecutor = new MigrationCommandExecutor();
diff --git a/test/EFCore.Relational.Tests/Migrations/MigrationCommandListBuilderTest.cs b/test/EFCore.Relational.Tests/Migrations/MigrationCommandListBuilderTest.cs
index 8f658a5e3c6..87ff10c91d8 100644
--- a/test/EFCore.Relational.Tests/Migrations/MigrationCommandListBuilderTest.cs
+++ b/test/EFCore.Relational.Tests/Migrations/MigrationCommandListBuilderTest.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider;
@@ -136,7 +137,12 @@ private MigrationCommandListBuilder CreateBuilder()
typeMappingSource)),
generationHelper,
typeMappingSource,
+ new CurrentDbContext(new FakeDbContext()),
logger));
}
+
+ private class FakeDbContext : DbContext
+ {
+ }
}
}
diff --git a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs
index c42d84028c8..baf43c1dfd1 100644
--- a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs
+++ b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs
@@ -73,7 +73,8 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled()
{ typeof(IProperty), () => property },
{ typeof(TypeInfo), () => typeof(object).GetTypeInfo() },
{ typeof(Type), () => typeof(object) },
- { typeof(ValueConverter), () => new BoolToZeroOneConverter() }
+ { typeof(ValueConverter), () => new BoolToZeroOneConverter() },
+ { typeof(DbContext), () => new FakeDbContext() }
};
TestEventLogging(
@@ -108,6 +109,10 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled()
});
}
+ private class FakeDbContext : DbContext
+ {
+ }
+
private class FakeMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder) => throw new NotImplementedException();
diff --git a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs
index 1119e4d6cca..8967c730c1d 100644
--- a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs
+++ b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs
@@ -43,7 +43,8 @@ public void Configures_DbCommand()
var fakeConnection = CreateConnection();
var relationalCommand = CreateRelationalCommand(commandText: "CommandText");
- relationalCommand.ExecuteNonQuery(fakeConnection, null, null);
+ relationalCommand.ExecuteNonQuery(
+ new RelationalCommandParameterObject(fakeConnection, null, null, null));
Assert.Equal(1, fakeConnection.DbConnections.Count);
Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count);
@@ -64,7 +65,8 @@ public void Configures_DbCommand_with_transaction()
var relationalCommand = CreateRelationalCommand();
- relationalCommand.ExecuteNonQuery(fakeConnection, null, null);
+ relationalCommand.ExecuteNonQuery(
+ new RelationalCommandParameterObject(fakeConnection, null, null, null));
Assert.Equal(1, fakeConnection.DbConnections.Count);
Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count);
@@ -85,7 +87,8 @@ public void Configures_DbCommand_with_timeout()
var relationalCommand = CreateRelationalCommand();
- relationalCommand.ExecuteNonQuery(fakeConnection, null, null);
+ relationalCommand.ExecuteNonQuery(
+ new RelationalCommandParameterObject(fakeConnection, null, null, null));
Assert.Equal(1, fakeConnection.DbConnections.Count);
Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count);
@@ -118,7 +121,8 @@ public void Can_ExecuteNonQuery()
var relationalCommand = CreateRelationalCommand();
var result = relationalCommand.ExecuteNonQuery(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Equal(1, result);
@@ -157,7 +161,8 @@ public virtual async Task Can_ExecuteNonQueryAsync()
var relationalCommand = CreateRelationalCommand();
var result = await relationalCommand.ExecuteNonQueryAsync(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Equal(1, result);
@@ -196,7 +201,8 @@ public void Can_ExecuteScalar()
var relationalCommand = CreateRelationalCommand();
var result = (string)relationalCommand.ExecuteScalar(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Equal("ExecuteScalar Result", result);
@@ -235,7 +241,8 @@ public async Task Can_ExecuteScalarAsync()
var relationalCommand = CreateRelationalCommand();
var result = (string)await relationalCommand.ExecuteScalarAsync(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Equal("ExecuteScalar Result", result);
@@ -276,7 +283,8 @@ public void Can_ExecuteReader()
var relationalCommand = CreateRelationalCommand();
var result = relationalCommand.ExecuteReader(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Same(dbDataReader, result.DbDataReader);
Assert.Equal(0, fakeDbConnection.CloseCount);
@@ -324,7 +332,8 @@ public async Task Can_ExecuteReaderAsync()
var relationalCommand = CreateRelationalCommand();
var result = await relationalCommand.ExecuteReaderAsync(
- new FakeRelationalConnection(options), null, null);
+ new RelationalCommandParameterObject(
+ new FakeRelationalConnection(options), null, null, null));
Assert.Same(dbDataReader, result.DbDataReader);
Assert.Equal(0, fakeDbConnection.CloseCount);
@@ -353,42 +362,48 @@ public static TheoryData CommandActions
{
new CommandAction(
(connection, command, parameterValues, logger)
- => command.ExecuteNonQuery(connection, parameterValues, logger)),
+ => command.ExecuteNonQuery(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteNonQuery,
false
},
{
new CommandAction(
(connection, command, parameterValues, logger)
- => command.ExecuteScalar(connection, parameterValues, logger)),
+ => command.ExecuteScalar(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteScalar,
false
},
{
new CommandAction(
(connection, command, parameterValues, logger)
- => command.ExecuteReader(connection, parameterValues, logger)),
+ => command.ExecuteReader(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteReader,
false
},
{
new CommandFunc(
(connection, command, parameterValues, logger)
- => command.ExecuteNonQueryAsync(connection, parameterValues, logger)),
+ => command.ExecuteNonQueryAsync(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteNonQuery,
true
},
{
new CommandFunc(
(connection, command, parameterValues, logger)
- => command.ExecuteScalarAsync(connection, parameterValues, logger)),
+ => command.ExecuteScalarAsync(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteScalar,
true
},
{
new CommandFunc(
(connection, command, parameterValues, logger)
- => command.ExecuteReaderAsync(connection, parameterValues, logger)),
+ => command.ExecuteReaderAsync(
+ new RelationalCommandParameterObject(connection, parameterValues, null, logger))),
DbCommandMethod.ExecuteReader,
true
}
diff --git a/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs b/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs
index e1087be7253..17ccf714173 100644
--- a/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs
+++ b/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs
@@ -588,6 +588,7 @@ private static ModificationCommandBatchFactoryDependencies CreateDependencies(
new RelationalValueBufferFactoryDependencies(
typeMappingSource,
new CoreSingletonOptions())),
+ new CurrentDbContext(new FakeDbContext()),
logger);
}
@@ -613,6 +614,10 @@ public RawSqlCommand CreateStoreCommandBase()
=> CreateStoreCommand();
}
+ private class FakeDbContext : DbContext
+ {
+ }
+
private const string ConnectionString = "Fake Connection String";
private static FakeRelationalConnection CreateConnection(DbDataReader dbDataReader)
diff --git a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs
index c86c4de143e..2a95080a73b 100644
--- a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Storage;
@@ -81,7 +80,7 @@ public IRelationalCommandBuilder DecrementIndent()
return this;
}
-
+
public int CommandTextLength => Instance.Length;
}
@@ -101,14 +100,12 @@ public TestRelationalCommand(
public IReadOnlyList Parameters => _realRelationalCommand.Parameters;
- public int ExecuteNonQuery(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public int ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = _realRelationalCommand.ExecuteNonQuery(connection, parameterValues, logger);
+ var result = _realRelationalCommand.ExecuteNonQuery(parameterObject);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
@@ -119,13 +116,13 @@ public int ExecuteNonQuery(
}
public Task ExecuteNonQueryAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = new CancellationToken())
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = _realRelationalCommand.ExecuteNonQueryAsync(connection, parameterValues, logger, cancellationToken);
+ var result = _realRelationalCommand.ExecuteNonQueryAsync(parameterObject, cancellationToken);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
@@ -135,14 +132,12 @@ public Task ExecuteNonQueryAsync(
return result;
}
- public object ExecuteScalar(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public object ExecuteScalar(RelationalCommandParameterObject parameterObject)
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = _realRelationalCommand.ExecuteScalar(connection, parameterValues, logger);
+ var result = _realRelationalCommand.ExecuteScalar(parameterObject);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
@@ -153,13 +148,13 @@ public object ExecuteScalar(
}
public async Task ExecuteScalarAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = new CancellationToken())
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = await _realRelationalCommand.ExecuteScalarAsync(connection, parameterValues, logger, cancellationToken);
+ var result = await _realRelationalCommand.ExecuteScalarAsync(parameterObject, cancellationToken);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
@@ -169,14 +164,12 @@ public async Task ExecuteScalarAsync(
return result;
}
- public RelationalDataReader ExecuteReader(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject)
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = _realRelationalCommand.ExecuteReader(connection, parameterValues, logger);
+ var result = _realRelationalCommand.ExecuteReader(parameterObject);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
@@ -188,13 +181,13 @@ public RelationalDataReader ExecuteReader(
}
public async Task ExecuteReaderAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = new CancellationToken())
{
+ var connection = parameterObject.Connection;
var errorNumber = PreExecution(connection);
- var result = await _realRelationalCommand.ExecuteReaderAsync(connection, parameterValues, logger, cancellationToken);
+ var result = await _realRelationalCommand.ExecuteReaderAsync(parameterObject, cancellationToken);
if (errorNumber.HasValue)
{
connection.DbConnection.Close();
diff --git a/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs b/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs
index 5eca5acdd3d..e58d196cdef 100644
--- a/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs
+++ b/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs
@@ -6,7 +6,6 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
-using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
@@ -261,47 +260,35 @@ private class FakeRelationalCommand : IRelationalCommand
public IReadOnlyDictionary ParameterValues => throw new NotImplementedException();
- public int ExecuteNonQuery(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public int ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
{
return 0;
}
public Task ExecuteNonQueryAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
=> Task.FromResult(0);
- public RelationalDataReader ExecuteReader(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject)
{
throw new NotImplementedException();
}
public Task ExecuteReaderAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
- public object ExecuteScalar(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public object ExecuteScalar(RelationalCommandParameterObject parameterObject)
{
throw new NotImplementedException();
}
public Task ExecuteScalarAsync(
- IRelationalConnection connection, IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
diff --git a/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs b/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs
index 0afcdf9c419..d9fffaf3592 100644
--- a/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs
+++ b/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs
@@ -7,7 +7,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
@@ -236,48 +235,33 @@ public FakeRelationalCommand(FakeRawSqlCommandBuilder commandBuilder)
public IReadOnlyDictionary ParameterValues => throw new NotImplementedException();
- public int ExecuteNonQuery(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public int ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
{
throw new NotImplementedException();
}
public Task ExecuteNonQueryAsync(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
- public object ExecuteScalar(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger)
+ public object ExecuteScalar(RelationalCommandParameterObject parameterObject)
=> Interlocked.Add(ref _commandBuilder._current, _commandBuilder._blockSize);
public Task ExecuteScalarAsync(
- IRelationalConnection connection,
- IReadOnlyDictionary parameterValues,
- IDiagnosticsLogger logger,
+ RelationalCommandParameterObject parameterObject,
CancellationToken cancellationToken = default)
=> Task.FromResult(Interlocked.Add(ref _commandBuilder._current, _commandBuilder._blockSize));
- public RelationalDataReader ExecuteReader(
- IRelationalConnection connection,
- IReadOnlyDictionary