diff --git a/src/EFCore.Relational/Diagnostics/CommandCorrelatedEventData.cs b/src/EFCore.Relational/Diagnostics/CommandCorrelatedEventData.cs index 00573339970..86261abeafd 100644 --- a/src/EFCore.Relational/Diagnostics/CommandCorrelatedEventData.cs +++ b/src/EFCore.Relational/Diagnostics/CommandCorrelatedEventData.cs @@ -24,6 +24,7 @@ public class CommandCorrelatedEventData : DbContextEventData /// A correlation ID that identifies the instance being used. /// Indicates whether or not the command was executed asynchronously. /// The start time of this event. + [Obsolete("Use the overload with CommandSource")] public CommandCorrelatedEventData( EventDefinitionBase eventDefinition, Func messageGenerator, @@ -34,6 +35,45 @@ public CommandCorrelatedEventData( Guid connectionId, bool async, DateTimeOffset startTime) + : this( + eventDefinition, + messageGenerator, + connection, + context, + executeMethod, + commandId, + connectionId, + async, + startTime, + CommandSource.Unknown) + { + + } + + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The being used. + /// 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. + /// The start time of this event. + /// Source of the command. + public CommandCorrelatedEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + DbConnection connection, + DbContext? context, + DbCommandMethod executeMethod, + Guid commandId, + Guid connectionId, + bool async, + DateTimeOffset startTime, + CommandSource commandSource) : base(eventDefinition, messageGenerator, context) { Connection = connection; @@ -42,6 +82,7 @@ public CommandCorrelatedEventData( ExecuteMethod = executeMethod; IsAsync = async; StartTime = startTime; + CommandSource = commandSource; } /// @@ -73,5 +114,10 @@ public CommandCorrelatedEventData( /// The start time of this event. /// public virtual DateTimeOffset StartTime { get; } + + /// + /// Source of the command. + /// + public virtual CommandSource CommandSource { get; } } } diff --git a/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs b/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs index c2e97c9f7dd..fa3f1450207 100644 --- a/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs +++ b/src/EFCore.Relational/Diagnostics/CommandEndEventData.cs @@ -28,6 +28,7 @@ public class CommandEndEventData : CommandEventData /// Indicates whether or not the application allows logging of parameter values. /// The start time of this event. /// The duration this event. + [Obsolete("Use the overload with CommandSource")] public CommandEndEventData( EventDefinitionBase eventDefinition, Func messageGenerator, @@ -55,6 +56,51 @@ public CommandEndEventData( startTime) => Duration = duration; + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The being used. + /// 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. + /// Source of the command. + /// The duration this event. + public CommandEndEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + DbConnection connection, + DbCommand command, + DbContext? context, + DbCommandMethod executeMethod, + Guid commandId, + Guid connectionId, + bool async, + bool logParameterValues, + DateTimeOffset startTime, + CommandSource commandSource, + TimeSpan duration) + : base( + eventDefinition, + messageGenerator, + connection, + command, + context, + executeMethod, + commandId, + connectionId, + async, + logParameterValues, + startTime, + commandSource) + => Duration = duration; + /// /// The duration this event. /// diff --git a/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs b/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs index d0b78e85ec6..2bd018253ac 100644 --- a/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs +++ b/src/EFCore.Relational/Diagnostics/CommandErrorEventData.cs @@ -28,6 +28,7 @@ public class CommandErrorEventData : CommandEndEventData, IErrorEventData /// Indicates whether or not the application allows logging of parameter values. /// The start time of this event. /// The duration this event. + [Obsolete("Use the overload with CommandSource")] public CommandErrorEventData( EventDefinitionBase eventDefinition, Func messageGenerator, @@ -55,7 +56,59 @@ public CommandErrorEventData( logParameterValues, startTime, duration) - => Exception = exception; + { + Exception = exception; + } + + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The being used. + /// 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. + /// Source of the command. + /// The duration this event. + public CommandErrorEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + DbConnection connection, + DbCommand command, + DbContext? context, + DbCommandMethod executeMethod, + Guid commandId, + Guid connectionId, + Exception exception, + bool async, + bool logParameterValues, + DateTimeOffset startTime, + CommandSource commandSource, + TimeSpan duration) + : base( + eventDefinition, + messageGenerator, + connection, + command, + context, + executeMethod, + commandId, + connectionId, + async, + logParameterValues, + startTime, + commandSource, + duration) + { + Exception = exception; + } /// /// The exception that was thrown when execution failed. diff --git a/src/EFCore.Relational/Diagnostics/CommandEventData.cs b/src/EFCore.Relational/Diagnostics/CommandEventData.cs index 6c84b669c3c..f76995d991b 100644 --- a/src/EFCore.Relational/Diagnostics/CommandEventData.cs +++ b/src/EFCore.Relational/Diagnostics/CommandEventData.cs @@ -27,6 +27,7 @@ public class CommandEventData : CommandCorrelatedEventData /// 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. + [Obsolete("Use the overload with CommandSource")] public CommandEventData( EventDefinitionBase eventDefinition, Func messageGenerator, @@ -39,6 +40,50 @@ public CommandEventData( bool async, bool logParameterValues, DateTimeOffset startTime) + : this( + eventDefinition, + messageGenerator, + connection, + command, + context, + executeMethod, + commandId, + connectionId, + async, + logParameterValues, + startTime, + CommandSource.Unknown) + { + } + + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The being used. + /// 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. + /// Source of the command. + public CommandEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + DbConnection connection, + DbCommand command, + DbContext? context, + DbCommandMethod executeMethod, + Guid commandId, + Guid connectionId, + bool async, + bool logParameterValues, + DateTimeOffset startTime, + CommandSource commandSource) : base( eventDefinition, messageGenerator, @@ -48,7 +93,8 @@ public CommandEventData( commandId, connectionId, async, - startTime) + startTime, + commandSource) { Command = command; LogParameterValues = logParameterValues; diff --git a/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs b/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs index 3087871a965..6e0b18655cd 100644 --- a/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs +++ b/src/EFCore.Relational/Diagnostics/CommandExecutedEventData.cs @@ -28,6 +28,7 @@ public class CommandExecutedEventData : CommandEndEventData /// Indicates whether or not the application allows logging of parameter values. /// The start time of this event. /// The duration this event. + [Obsolete("Use the overload with CommandSource")] public CommandExecutedEventData( EventDefinitionBase eventDefinition, Func messageGenerator, @@ -57,6 +58,54 @@ public CommandExecutedEventData( duration) => Result = result; + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The being used. + /// 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. + /// Source of the command. + /// The duration this event. + public CommandExecutedEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + DbConnection connection, + DbCommand command, + DbContext? context, + DbCommandMethod executeMethod, + Guid commandId, + Guid connectionId, + object? result, + bool async, + bool logParameterValues, + DateTimeOffset startTime, + CommandSource commandSource, + TimeSpan duration) + : base( + eventDefinition, + messageGenerator, + connection, + command, + context, + executeMethod, + commandId, + connectionId, + async, + logParameterValues, + startTime, + commandSource, + duration) + => Result = result; + /// /// The result of executing the command. /// diff --git a/src/EFCore.Relational/Diagnostics/CommandSource.cs b/src/EFCore.Relational/Diagnostics/CommandSource.cs new file mode 100644 index 00000000000..0d9fd4b1df1 --- /dev/null +++ b/src/EFCore.Relational/Diagnostics/CommandSource.cs @@ -0,0 +1,59 @@ +// 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.Data.Common; + +namespace Microsoft.EntityFrameworkCore.Diagnostics +{ + /// + /// Enum used by , and subclasses to indicate the + /// source of the being used to execute the command. + /// + public enum CommandSource + { + /// + /// Unknown + /// + Unknown, + + /// + /// Linq Query + /// + LinqQuery, + + /// + /// Save Changes + /// + SaveChanges, + + /// + /// Migrations + /// + Migrations, + + /// + /// FromSqlQuery + /// + FromSqlQuery, + + /// + /// ExecuteSqlRaw + /// + ExecuteSqlRaw, + + /// + /// ValueGenerator + /// + ValueGenerator, + + /// + /// Scaffolding + /// + Scaffolding, + + /// + /// BulkUpdate + /// + BulkUpdate + } +} diff --git a/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs index 03226372cbc..9a7726606ed 100644 --- a/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs +++ b/src/EFCore.Relational/Diagnostics/IRelationalCommandDiagnosticsLogger.cs @@ -23,6 +23,7 @@ public interface IRelationalCommandDiagnosticsLogger : IDiagnosticsLogger The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// An intercepted result. InterceptionResult CommandCreating( IRelationalConnection connection, @@ -30,7 +31,8 @@ InterceptionResult CommandCreating( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime); + DateTimeOffset startTime, + CommandSource commandSource); /// /// Logs for the event. @@ -43,6 +45,7 @@ InterceptionResult CommandCreating( /// The correlation ID associated with the being used. /// The time that execution began. /// The duration of the command creation. + /// Source of the command. /// An intercepted result. DbCommand CommandCreated( IRelationalConnection connection, @@ -52,6 +55,7 @@ DbCommand CommandCreated( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration); /// @@ -63,6 +67,7 @@ DbCommand CommandCreated( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// An intercepted result. InterceptionResult CommandReaderExecuting( IRelationalConnection connection, @@ -70,7 +75,8 @@ InterceptionResult CommandReaderExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime); + DateTimeOffset startTime, + CommandSource commandSource); /// /// Logs for the event. @@ -81,6 +87,7 @@ InterceptionResult CommandReaderExecuting( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// An intercepted result. InterceptionResult CommandScalarExecuting( IRelationalConnection connection, @@ -88,7 +95,8 @@ InterceptionResult CommandScalarExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime); + DateTimeOffset startTime, + CommandSource commandSource); /// /// Logs for the event. @@ -99,6 +107,7 @@ InterceptionResult CommandScalarExecuting( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// An intercepted result. InterceptionResult CommandNonQueryExecuting( IRelationalConnection connection, @@ -106,7 +115,8 @@ InterceptionResult CommandNonQueryExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime); + DateTimeOffset startTime, + CommandSource commandSource); /// /// Logs for the event. @@ -117,6 +127,7 @@ InterceptionResult CommandNonQueryExecuting( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// A to observe while waiting for the task to complete. /// An intercepted result. /// If the is canceled. @@ -127,6 +138,7 @@ ValueTask> CommandReaderExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default); /// @@ -138,6 +150,7 @@ ValueTask> CommandReaderExecutingAsync( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// A to observe while waiting for the task to complete. /// An intercepted result. /// If the is canceled. @@ -148,6 +161,7 @@ ValueTask> CommandScalarExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default); /// @@ -159,6 +173,7 @@ ValueTask> CommandScalarExecutingAsync( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// A to observe while waiting for the task to complete. /// An intercepted result. /// If the is canceled. @@ -169,6 +184,7 @@ ValueTask> CommandNonQueryExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default); /// @@ -181,6 +197,7 @@ ValueTask> CommandNonQueryExecutingAsync( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// The result of execution, which may have been modified by an interceptor. DbDataReader CommandReaderExecuted( @@ -191,6 +208,7 @@ DbDataReader CommandReaderExecuted( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration); /// @@ -203,6 +221,7 @@ DbDataReader CommandReaderExecuted( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// The result of execution, which may have been modified by an interceptor. object? CommandScalarExecuted( @@ -213,6 +232,7 @@ DbDataReader CommandReaderExecuted( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration); /// @@ -225,6 +245,7 @@ DbDataReader CommandReaderExecuted( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// The result of execution, which may have been modified by an interceptor. int CommandNonQueryExecuted( @@ -235,6 +256,7 @@ int CommandNonQueryExecuted( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration); /// @@ -247,6 +269,7 @@ int CommandNonQueryExecuted( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// A to observe while waiting for the task to complete. /// The result of execution, which may have been modified by an interceptor. @@ -259,6 +282,7 @@ ValueTask CommandReaderExecutedAsync( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default); @@ -272,6 +296,7 @@ ValueTask CommandReaderExecutedAsync( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// A to observe while waiting for the task to complete. /// The result of execution, which may have been modified by an interceptor. @@ -284,6 +309,7 @@ ValueTask CommandReaderExecutedAsync( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default); @@ -297,6 +323,7 @@ ValueTask CommandReaderExecutedAsync( /// The correlation ID associated with the being used. /// The return value from the underlying method execution. /// The time that execution began. + /// Source of the command. /// The duration of the command execution, not including consuming results. /// A to observe while waiting for the task to complete. /// The result of execution, which may have been modified by an interceptor. @@ -309,6 +336,7 @@ ValueTask CommandNonQueryExecutedAsync( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default); @@ -323,6 +351,7 @@ ValueTask CommandNonQueryExecutedAsync( /// The correlation ID associated with the being used. /// The exception that caused this failure. /// The time that execution began. + /// Source of the command. /// The amount of time that passed until the exception was raised. void CommandError( IRelationalConnection connection, @@ -333,6 +362,7 @@ void CommandError( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration); /// @@ -346,6 +376,7 @@ void CommandError( /// The correlation ID associated with the being used. /// The exception that caused this failure. /// The time that execution began. + /// Source of the command. /// The amount of time that passed until the exception was raised. /// A to observe while waiting for the task to complete. /// A representing the async operation. @@ -359,6 +390,7 @@ Task CommandErrorAsync( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default); diff --git a/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs b/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs index 9c28b2af44c..9d70c691687 100644 --- a/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs +++ b/src/EFCore.Relational/Diagnostics/Internal/RelationalCommandDiagnosticsLogger.cs @@ -66,7 +66,8 @@ public virtual InterceptionResult CommandCreating( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) { _suppressCommandCreateExpiration = startTime + _loggingCacheTime; @@ -92,6 +93,7 @@ public virtual InterceptionResult CommandCreating( connectionId, async: false, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -113,6 +115,7 @@ private CommandCorrelatedEventData BroadcastCommandCreating( Guid connectionId, bool async, DateTimeOffset startTime, + CommandSource commandSource, EventDefinition definition, bool diagnosticSourceEnabled, bool simpleLogEnabled) @@ -126,7 +129,8 @@ private CommandCorrelatedEventData BroadcastCommandCreating( commandId, connectionId, async, - startTime); + startTime, + commandSource); DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); @@ -158,6 +162,7 @@ public virtual DbCommand CommandCreated( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { var definition = RelationalResources.LogCommandCreated(this); @@ -183,6 +188,7 @@ public virtual DbCommand CommandCreated( connectionId, async: false, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -206,6 +212,7 @@ private CommandEndEventData BroadcastCommandCreated( Guid connectionId, bool async, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, EventDefinition definition, bool diagnosticSourceEnabled, @@ -223,6 +230,7 @@ private CommandEndEventData BroadcastCommandCreated( async, false, startTime, + commandSource, duration); DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); @@ -253,7 +261,8 @@ public virtual InterceptionResult CommandReaderExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -286,6 +295,7 @@ public virtual InterceptionResult CommandReaderExecuting( connectionId, false, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -311,7 +321,8 @@ public virtual InterceptionResult CommandScalarExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -344,6 +355,7 @@ public virtual InterceptionResult CommandScalarExecuting( connectionId, false, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -369,7 +381,8 @@ public virtual InterceptionResult CommandNonQueryExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -402,6 +415,7 @@ public virtual InterceptionResult CommandNonQueryExecuting( connectionId, false, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -428,6 +442,7 @@ public virtual ValueTask> CommandReaderExecutin Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -461,6 +476,7 @@ public virtual ValueTask> CommandReaderExecutin connectionId, async: true, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -487,6 +503,7 @@ public virtual ValueTask> CommandScalarExecutingAsync Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -520,6 +537,7 @@ public virtual ValueTask> CommandScalarExecutingAsync connectionId, async: true, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -546,6 +564,7 @@ public virtual ValueTask> CommandNonQueryExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) { _suppressCommandExecuteExpiration = startTime + _loggingCacheTime; @@ -579,6 +598,7 @@ public virtual ValueTask> CommandNonQueryExecutingAsync( connectionId, async: true, startTime, + commandSource, definition, diagnosticSourceEnabled, simpleLogEnabled); @@ -601,6 +621,7 @@ private CommandEventData BroadcastCommandExecuting( Guid connectionId, bool async, DateTimeOffset startTime, + CommandSource commandSource, EventDefinition definition, bool diagnosticSourceEnabled, bool simpleLogEnabled) @@ -616,7 +637,8 @@ private CommandEventData BroadcastCommandExecuting( connectionId, async, ShouldLogParameterValues(command), - startTime); + startTime, + commandSource); DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); @@ -653,6 +675,7 @@ public virtual DbDataReader CommandReaderExecuted( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { var definition = RelationalResources.LogExecutedCommand(this); @@ -686,6 +709,7 @@ public virtual DbDataReader CommandReaderExecuted( methodResult, async: false, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -714,6 +738,7 @@ public virtual DbDataReader CommandReaderExecuted( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { var definition = RelationalResources.LogExecutedCommand(this); @@ -747,6 +772,7 @@ public virtual DbDataReader CommandReaderExecuted( methodResult, async: false, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -775,6 +801,7 @@ public virtual int CommandNonQueryExecuted( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { var definition = RelationalResources.LogExecutedCommand(this); @@ -808,6 +835,7 @@ public virtual int CommandNonQueryExecuted( methodResult, async: false, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -836,6 +864,7 @@ public virtual ValueTask CommandReaderExecutedAsync( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) { @@ -870,6 +899,7 @@ public virtual ValueTask CommandReaderExecutedAsync( methodResult, async: true, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -898,6 +928,7 @@ public virtual ValueTask CommandReaderExecutedAsync( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) { @@ -932,6 +963,7 @@ public virtual ValueTask CommandReaderExecutedAsync( methodResult, async: true, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -960,6 +992,7 @@ public virtual ValueTask CommandNonQueryExecutedAsync( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) { @@ -994,6 +1027,7 @@ public virtual ValueTask CommandNonQueryExecutedAsync( methodResult, async: true, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -1018,6 +1052,7 @@ private CommandExecutedEventData BroadcastCommandExecuted( object? methodResult, bool async, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, EventDefinition definition, bool diagnosticSourceEnabled, @@ -1036,6 +1071,7 @@ private CommandExecutedEventData BroadcastCommandExecuted( async, ShouldLogParameterValues(command), startTime, + commandSource, duration); DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); @@ -1075,6 +1111,7 @@ public virtual void CommandError( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { var definition = RelationalResources.LogCommandFailed(this); @@ -1094,6 +1131,7 @@ public virtual void CommandError( exception, false, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -1136,6 +1174,7 @@ public virtual Task CommandErrorAsync( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) { @@ -1156,6 +1195,7 @@ public virtual Task CommandErrorAsync( exception, true, startTime, + commandSource, duration, definition, diagnosticSourceEnabled, @@ -1180,6 +1220,7 @@ private CommandErrorEventData BroadcastCommandError( Exception exception, bool async, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, EventDefinition definition, bool diagnosticSourceEnabled, @@ -1198,6 +1239,7 @@ private CommandErrorEventData BroadcastCommandError( async, ShouldLogParameterValues(command), startTime, + commandSource, duration); DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); diff --git a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs index be1c1ea50ba..86daf2aa99e 100644 --- a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs @@ -244,7 +244,7 @@ public static int ExecuteSqlRaw( rawSqlCommand.ParameterValues, null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, - logger)); + logger, CommandSource.ExecuteSqlRaw)); } finally { @@ -434,7 +434,7 @@ public static async Task ExecuteSqlRawAsync( rawSqlCommand.ParameterValues, null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, - logger), + logger, CommandSource.ExecuteSqlRaw), cancellationToken) .ConfigureAwait(false); } diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs index 016bcf4e05f..f263b5844ec 100644 --- a/src/EFCore.Relational/Migrations/HistoryRepository.cs +++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -141,7 +142,7 @@ public virtual bool Exists() null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger))); + Dependencies.CommandLogger, CommandSource.Migrations))); /// /// Checks whether or not the history table exists. @@ -161,7 +162,7 @@ await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync( null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger), + Dependencies.CommandLogger, CommandSource.Migrations), cancellationToken).ConfigureAwait(false)); /// @@ -226,7 +227,7 @@ public virtual IReadOnlyList GetAppliedMigrations() null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger)); + Dependencies.CommandLogger, CommandSource.Migrations)); while (reader.Read()) { rows.Add(new HistoryRow(reader.DbDataReader.GetString(0), reader.DbDataReader.GetString(1))); @@ -260,7 +261,7 @@ public virtual async Task> GetAppliedMigrationsAsync( null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger), + Dependencies.CommandLogger, CommandSource.Migrations), cancellationToken).ConfigureAwait(false); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index 8686046b7df..6992403d32a 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -122,7 +122,7 @@ public virtual void Migrate(string? targetMigration = null) null, null, _currentContext.Context, - _commandLogger)); + _commandLogger, CommandSource.Migrations)); } var commandLists = GetMigrationCommandLists(_historyRepository.GetAppliedMigrations(), targetMigration); @@ -160,7 +160,7 @@ await command.ExecuteNonQueryAsync( null, null, _currentContext.Context, - _commandLogger), + _commandLogger, CommandSource.Migrations), cancellationToken) .ConfigureAwait(false); } diff --git a/src/EFCore.Relational/Migrations/MigrationCommand.cs b/src/EFCore.Relational/Migrations/MigrationCommand.cs index 875c218a081..2d9f2409614 100644 --- a/src/EFCore.Relational/Migrations/MigrationCommand.cs +++ b/src/EFCore.Relational/Migrations/MigrationCommand.cs @@ -71,7 +71,7 @@ public virtual int ExecuteNonQuery( parameterValues, null, _context, - CommandLogger)); + CommandLogger, CommandSource.Migrations)); /// /// Executes the command and returns the number of rows affected. @@ -91,7 +91,7 @@ public virtual Task ExecuteNonQueryAsync( parameterValues, null, _context, - CommandLogger), + CommandLogger, CommandSource.Migrations), cancellationToken); } } diff --git a/src/EFCore.Relational/Query/Internal/FromSqlQueryingEnumerable.cs b/src/EFCore.Relational/Query/Internal/FromSqlQueryingEnumerable.cs index 77e7f316296..61a1b7a1d19 100644 --- a/src/EFCore.Relational/Query/Internal/FromSqlQueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Internal/FromSqlQueryingEnumerable.cs @@ -106,7 +106,7 @@ public virtual DbCommand CreateDbCommand() null, null, null, - _detailedErrorsEnabled), + _detailedErrorsEnabled, CommandSource.FromSqlQuery), Guid.Empty, (DbCommandMethod)(-1)); @@ -238,7 +238,7 @@ private static bool InitializeReader(Enumerator enumerator) enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorsEnabled)); + enumerator._detailedErrorsEnabled, CommandSource.FromSqlQuery)); enumerator._indexMap = BuildIndexMap(enumerator._columnNames, enumerator._dataReader.DbDataReader); @@ -353,7 +353,7 @@ private static async Task InitializeReaderAsync(AsyncEnumerator enumerator enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorsEnabled), + enumerator._detailedErrorsEnabled, CommandSource.FromSqlQuery), cancellationToken) .ConfigureAwait(false); diff --git a/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs b/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs index d47a18d6e1a..0fb2c4017a2 100644 --- a/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs @@ -101,7 +101,7 @@ public virtual DbCommand CreateDbCommand() _relationalQueryContext.ParameterValues, null, null, - null), + null, CommandSource.LinqQuery), Guid.Empty, (DbCommandMethod)(-1)); @@ -234,7 +234,8 @@ private static bool InitializeReader(Enumerator enumerator) enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorsEnabled)); + enumerator._detailedErrorsEnabled, + CommandSource.LinqQuery)); enumerator._dbDataReader = dataReader.DbDataReader; enumerator._resultCoordinator = new SingleQueryResultCoordinator(); @@ -381,7 +382,7 @@ private static async Task InitializeReaderAsync(AsyncEnumerator enumerator enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorsEnabled), + enumerator._detailedErrorsEnabled, CommandSource.LinqQuery), cancellationToken) .ConfigureAwait(false); enumerator._dbDataReader = dataReader.DbDataReader; diff --git a/src/EFCore.Relational/Query/Internal/SplitQueryingEnumerable.cs b/src/EFCore.Relational/Query/Internal/SplitQueryingEnumerable.cs index c9be339524f..9297bcbf29b 100644 --- a/src/EFCore.Relational/Query/Internal/SplitQueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Internal/SplitQueryingEnumerable.cs @@ -108,7 +108,7 @@ public virtual DbCommand CreateDbCommand() null, null, null, - _detailedErrorsEnabled), + _detailedErrorsEnabled, CommandSource.LinqQuery), Guid.Empty, (DbCommandMethod)(-1)); @@ -229,7 +229,8 @@ private static bool InitializeReader(Enumerator enumerator) enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorsEnabled)); + enumerator._detailedErrorsEnabled, + CommandSource.LinqQuery)); enumerator._dbDataReader = dataReader.DbDataReader; enumerator._resultCoordinator = new SplitQueryResultCoordinator(); @@ -380,7 +381,7 @@ private static async Task InitializeReaderAsync(AsyncEnumerator enumerator enumerator._relationalCommandCache.ReaderColumns, enumerator._relationalQueryContext.Context, enumerator._relationalQueryContext.CommandLogger, - enumerator._detailedErrorEnabled), + enumerator._detailedErrorEnabled, CommandSource.LinqQuery), cancellationToken) .ConfigureAwait(false); enumerator._dbDataReader = dataReader.DbDataReader; diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs index 1e22b63c718..447221d97db 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs @@ -1414,7 +1414,7 @@ static RelationalDataReader InitializeReader( relationalCommandCache.ReaderColumns, queryContext.Context, queryContext.CommandLogger, - detailedErrorsEnabled)); + detailedErrorsEnabled, CommandSource.LinqQuery)); } resultCoordinator.SetDataReader(collectionId, dataReader); @@ -1503,7 +1503,7 @@ async Task InitializeReaderAsync( relationalCommandCache.ReaderColumns, queryContext.Context, queryContext.CommandLogger, - detailedErrorsEnabled), + detailedErrorsEnabled, CommandSource.LinqQuery), cancellationToken) .ConfigureAwait(false); } @@ -1743,7 +1743,7 @@ static RelationalDataReader InitializeReader( relationalCommandCache.ReaderColumns, queryContext.Context, queryContext.CommandLogger, - detailedErrorsEnabled)); + detailedErrorsEnabled, CommandSource.LinqQuery)); } resultCoordinator.SetDataReader(collectionId, dataReader); @@ -1816,14 +1816,15 @@ async Task InitializeReaderAsync( var relationalCommand = relationalCommandCache.GetRelationalCommand(queryContext.ParameterValues); return await relationalCommand.ExecuteReaderAsync( - new RelationalCommandParameterObject( - queryContext.Connection, - queryContext.ParameterValues, - relationalCommandCache.ReaderColumns, - queryContext.Context, - queryContext.CommandLogger, - detailedErrorsEnabled), - cancellationToken) + new RelationalCommandParameterObject( + queryContext.Connection, + queryContext.ParameterValues, + relationalCommandCache.ReaderColumns, + queryContext.Context, + queryContext.CommandLogger, + detailedErrorsEnabled, + CommandSource.LinqQuery), + cancellationToken) .ConfigureAwait(false); } diff --git a/src/EFCore.Relational/Storage/RelationalCommand.cs b/src/EFCore.Relational/Storage/RelationalCommand.cs index 3ddf95e11b4..3976f00c1ac 100644 --- a/src/EFCore.Relational/Storage/RelationalCommand.cs +++ b/src/EFCore.Relational/Storage/RelationalCommand.cs @@ -101,7 +101,8 @@ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObj context, commandId, connection.ConnectionId, - startTime) + startTime, + parameterObject.CommandSource) ?? default; var nonQueryResult = interceptionResult.HasResult @@ -116,6 +117,7 @@ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObj connection.ConnectionId, nonQueryResult, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed) ?? nonQueryResult; } @@ -135,6 +137,7 @@ public virtual int ExecuteNonQuery(RelationalCommandParameterObject parameterObj connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed); throw; @@ -187,6 +190,7 @@ public virtual async Task ExecuteNonQueryAsync( commandId, connection.ConnectionId, startTime, + parameterObject.CommandSource, cancellationToken) .ConfigureAwait(false); @@ -204,6 +208,7 @@ public virtual async Task ExecuteNonQueryAsync( connection.ConnectionId, result, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed, cancellationToken) .ConfigureAwait(false); @@ -229,6 +234,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed, cancellationToken) .ConfigureAwait(false); @@ -275,7 +281,8 @@ await logger.CommandErrorAsync( context, commandId, connection.ConnectionId, - startTime) + startTime, + parameterObject.CommandSource) ?? default; var result = interceptionResult.HasResult @@ -290,6 +297,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, result, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed) ?? result; } @@ -309,6 +317,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed); throw; @@ -361,6 +370,7 @@ await logger.CommandErrorAsync( commandId, connection.ConnectionId, startTime, + parameterObject.CommandSource, cancellationToken) .ConfigureAwait(false); @@ -378,6 +388,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, result, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed, cancellationToken).ConfigureAwait(false); } @@ -402,6 +413,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed, cancellationToken) .ConfigureAwait(false); @@ -455,7 +467,8 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje context, commandId, connection.ConnectionId, - startTime); + startTime, + parameterObject.CommandSource); reader = interceptionResult.HasResult ? interceptionResult.Result @@ -469,6 +482,7 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje connection.ConnectionId, reader, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed); } else @@ -487,6 +501,7 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed); CleanupCommand(command, connection); @@ -568,6 +583,7 @@ public virtual async Task ExecuteReaderAsync( commandId, connection.ConnectionId, startTime, + parameterObject.CommandSource, cancellationToken) .ConfigureAwait(false); @@ -583,6 +599,7 @@ public virtual async Task ExecuteReaderAsync( connection.ConnectionId, reader, startTime, + parameterObject.CommandSource, _stopwatch.Elapsed, cancellationToken) .ConfigureAwait(false); @@ -605,6 +622,7 @@ await logger.CommandErrorAsync( connection.ConnectionId, exception, startTime, + parameterObject.CommandSource, DateTimeOffset.UtcNow - startTime, cancellationToken) .ConfigureAwait(false); @@ -675,14 +693,15 @@ public virtual DbCommand CreateDbCommand( _stopwatch.Restart(); var interceptionResult = logger.CommandCreating( - connection, commandMethod, context, commandId, connectionId, startTime); + connection, commandMethod, context, commandId, connectionId, startTime, + parameterObject.CommandSource); command = interceptionResult.HasResult ? interceptionResult.Result : connection.DbConnection.CreateCommand(); command = logger.CommandCreated( - connection, command, commandMethod, context, commandId, connectionId, startTime, _stopwatch.Elapsed); + connection, command, commandMethod, context, commandId, connectionId, startTime, parameterObject.CommandSource, _stopwatch.Elapsed); } else { diff --git a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs index 62d84760f17..5b75f27632a 100644 --- a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs +++ b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs @@ -42,6 +42,58 @@ public 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 expected columns if the reader needs to be buffered, or null otherwise. + /// The current instance, or null if it is not known. + /// A logger, or null if no logger is available. + /// Source of the command. + public RelationalCommandParameterObject( + IRelationalConnection connection, + IReadOnlyDictionary? parameterValues, + IReadOnlyList? readerColumns, + DbContext? context, + IRelationalCommandDiagnosticsLogger? logger, + CommandSource commandSource) + : this(connection, parameterValues, readerColumns, context, logger, detailedErrorsEnabled: false, commandSource) + { + } + + /// + /// + /// 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 expected columns if the reader needs to be buffered, or null otherwise. + /// The current instance, or null if it is not known. + /// A logger, or null if no logger is available. + /// A value indicating if detailed errors are enabled. + public RelationalCommandParameterObject( + IRelationalConnection connection, + IReadOnlyDictionary? parameterValues, + IReadOnlyList? readerColumns, + DbContext? context, + IRelationalCommandDiagnosticsLogger? logger, + bool detailedErrorsEnabled) : this(connection, parameterValues, readerColumns, context, + logger, detailedErrorsEnabled, CommandSource.Unknown) + { + } + /// /// /// Creates a new parameter object for the given parameters. @@ -57,13 +109,15 @@ public RelationalCommandParameterObject( /// The current instance, or null if it is not known. /// A logger, or null if no logger is available. /// A value indicating if detailed errors are enabled. + /// Source of the command. public RelationalCommandParameterObject( IRelationalConnection connection, IReadOnlyDictionary? parameterValues, IReadOnlyList? readerColumns, DbContext? context, IRelationalCommandDiagnosticsLogger? logger, - bool detailedErrorsEnabled) + bool detailedErrorsEnabled, + CommandSource commandSource) { Check.NotNull(connection, nameof(connection)); @@ -73,6 +127,7 @@ public RelationalCommandParameterObject( Context = context; Logger = logger; DetailedErrorsEnabled = detailedErrorsEnabled; + CommandSource = commandSource; } /// @@ -104,5 +159,10 @@ public RelationalCommandParameterObject( /// A value indicating if detailed errors are enabled. /// public bool DetailedErrorsEnabled { get; } + + /// + /// Source of the command. + /// + public CommandSource CommandSource { get; } } } diff --git a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs index 046328aabf8..15c4f891a10 100644 --- a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs +++ b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs @@ -249,7 +249,7 @@ public override void Execute(IRelationalConnection connection) storeCommand.ParameterValues, null, Dependencies.CurrentContext.Context, - Dependencies.Logger)); + Dependencies.Logger, CommandSource.SaveChanges)); Consume(dataReader); } catch (DbUpdateException) @@ -289,7 +289,7 @@ public override async Task ExecuteAsync( storeCommand.ParameterValues, null, Dependencies.CurrentContext.Context, - Dependencies.Logger), + Dependencies.Logger, CommandSource.SaveChanges), cancellationToken).ConfigureAwait(false); await ConsumeAsync(dataReader, cancellationToken).ConfigureAwait(false); } diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs index 3aed06a4eaa..efd009a958b 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using System.Transactions; using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; @@ -126,7 +127,7 @@ public override bool HasTables() null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger))! + Dependencies.CommandLogger, CommandSource.Migrations))! != 0); /// @@ -145,7 +146,7 @@ public override Task HasTablesAsync(CancellationToken cancellationToken = null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger), + Dependencies.CommandLogger, CommandSource.Migrations), cancellationToken: ct) .ConfigureAwait(false))! != 0, cancellationToken); @@ -216,7 +217,7 @@ private bool Exists(bool retryOnNotExists) null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger)); + Dependencies.CommandLogger, CommandSource.Migrations)); return true; } @@ -277,7 +278,7 @@ await _rawSqlCommandBuilder null, null, Dependencies.CurrentContext.Context, - Dependencies.CommandLogger), + Dependencies.CommandLogger, CommandSource.Migrations), ct) .ConfigureAwait(false); diff --git a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs index 0fc8c7e0357..72ff3e8ae5a 100644 --- a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs +++ b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs @@ -65,7 +65,7 @@ protected override long GetNewLowValue() parameterValues: null, readerColumns: null, context: null, - _commandLogger)), + _commandLogger, CommandSource.ValueGenerator)), typeof(long), CultureInfo.InvariantCulture)!; @@ -85,7 +85,7 @@ await _rawSqlCommandBuilder parameterValues: null, readerColumns: null, context: null, - _commandLogger), + _commandLogger, CommandSource.ValueGenerator), cancellationToken) .ConfigureAwait(false), typeof(long), diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs index 3080d962cb1..f5c9fb14972 100644 --- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs @@ -4,6 +4,7 @@ using System; using System.IO; using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; @@ -64,7 +65,7 @@ public override void Create() null, null, null, - Dependencies.CommandLogger)); + Dependencies.CommandLogger, CommandSource.Migrations)); Dependencies.Connection.Close(); } @@ -115,7 +116,7 @@ public override bool HasTables() null, null, null, - Dependencies.CommandLogger))!; + Dependencies.CommandLogger, CommandSource.Migrations))!; return count != 0; } diff --git a/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs b/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs index d4671fc9583..daa09cef329 100644 --- a/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs @@ -57,7 +57,7 @@ public virtual async Task Intercept_query_passively(bool async, bool inj protected class PassiveReaderCommandInterceptor : CommandInterceptorBase { public PassiveReaderCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.FromSqlQuery) { } } @@ -137,7 +137,7 @@ public virtual async Task Intercept_non_query_passively(bool async, bool inject) protected class PassiveNonQueryCommandInterceptor : CommandInterceptorBase { public PassiveNonQueryCommandInterceptor() - : base(DbCommandMethod.ExecuteNonQuery) + : base(DbCommandMethod.ExecuteNonQuery, CommandSource.ExecuteSqlRaw) { } } @@ -176,7 +176,7 @@ public virtual async Task Intercept_query_to_suppress_execution(bool asy protected class SuppressingReaderCommandInterceptor : CommandInterceptorBase { public SuppressingReaderCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.LinqQuery) { } @@ -233,7 +233,7 @@ public virtual async Task Intercept_query_to_suppress_command_creation(bool asyn protected class SuppressingCreateCommandInterceptor : CommandInterceptorBase { public SuppressingCreateCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.LinqQuery) { } @@ -368,7 +368,7 @@ public virtual async Task Intercept_non_query_to_suppress_execution(bool async, protected class SuppressingNonQueryCommandInterceptor : CommandInterceptorBase { public SuppressingNonQueryCommandInterceptor() - : base(DbCommandMethod.ExecuteNonQuery) + : base(DbCommandMethod.ExecuteNonQuery, CommandSource.ExecuteSqlRaw) { } @@ -426,7 +426,7 @@ public virtual async Task Intercept_query_to_mutate_command(bool async, protected class MutatingReaderCommandInterceptor : CommandInterceptorBase { public MutatingReaderCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.LinqQuery) { } @@ -556,7 +556,7 @@ protected class MutatingNonQueryCommandInterceptor : CommandInterceptorBase public readonly string MutatedSql; public MutatingNonQueryCommandInterceptor(CommandInterceptionTestBase testBase) - : base(DbCommandMethod.ExecuteNonQuery) + : base(DbCommandMethod.ExecuteNonQuery, CommandSource.ExecuteSqlRaw) { MutatedSql = testBase.NormalizeDelimitersInRawString("DELETE FROM [Singularity] WHERE [Id] = 78"); @@ -616,7 +616,7 @@ public virtual async Task Intercept_query_to_replace_execution(bool asyn protected class QueryReplacingReaderCommandInterceptor : CommandInterceptorBase { public QueryReplacingReaderCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.LinqQuery) { } @@ -762,7 +762,7 @@ protected class QueryReplacingNonQueryCommandInterceptor : CommandInterceptorBas private readonly string commandText; public QueryReplacingNonQueryCommandInterceptor(CommandInterceptionTestBase testBase) - : base(DbCommandMethod.ExecuteNonQuery) + : base(DbCommandMethod.ExecuteNonQuery, CommandSource.ExecuteSqlRaw) { commandText = testBase.NormalizeDelimitersInRawString("DELETE FROM [Singularity] WHERE [Id] = 77"); } @@ -838,7 +838,7 @@ public virtual async Task Intercept_query_to_replace_result(bool async, protected class ResultReplacingReaderCommandInterceptor : CommandInterceptorBase { public ResultReplacingReaderCommandInterceptor() - : base(DbCommandMethod.ExecuteReader) + : base(DbCommandMethod.ExecuteReader, CommandSource.LinqQuery) { } @@ -1045,7 +1045,7 @@ public virtual async Task Intercept_non_query_to_replace_result(bool async, bool protected class ResultReplacingNonQueryCommandInterceptor : CommandInterceptorBase { public ResultReplacingNonQueryCommandInterceptor() - : base(DbCommandMethod.ExecuteNonQuery) + : base(DbCommandMethod.ExecuteNonQuery, CommandSource.ExecuteSqlRaw) { } @@ -1648,10 +1648,16 @@ protected static void AssertSql(string expected, string actual) protected abstract class CommandInterceptorBase : IDbCommandInterceptor { private readonly DbCommandMethod _commandMethod; + private readonly CommandSource _commandSource; - protected CommandInterceptorBase(DbCommandMethod commandMethod) + protected CommandInterceptorBase(DbCommandMethod commandMethod) : this(commandMethod, CommandSource.Unknown) + { + } + + protected CommandInterceptorBase(DbCommandMethod commandMethod, CommandSource commandSource) { _commandMethod = commandMethod; + _commandSource = commandSource; } public DbContext Context { get; set; } @@ -1659,6 +1665,7 @@ protected CommandInterceptorBase(DbCommandMethod commandMethod) public string CommandText { get; set; } public Guid CommandId { get; set; } public Guid ConnectionId { get; set; } + public CommandSource CommandSource { get; set; } public bool AsyncCalled { get; set; } public bool SyncCalled { get; set; } public bool ExecutingCalled { get; set; } @@ -1878,11 +1885,13 @@ protected virtual void AssertExecuting(DbCommand command, CommandEventData event Assert.Equal(CommandId, eventData.CommandId); Assert.Equal(ConnectionId, eventData.ConnectionId); Assert.Equal(_commandMethod, eventData.ExecuteMethod); + //Assert.Equal(_commandSource, eventData.CommandSource); Context = eventData.Context; CommandText = command.CommandText; CommandId = eventData.CommandId; ConnectionId = eventData.ConnectionId; + CommandSource = eventData.CommandSource; ExecutingCalled = true; } @@ -1893,6 +1902,7 @@ protected virtual void AssertExecuted(DbCommand command, CommandExecutedEventDat Assert.Equal(CommandId, eventData.CommandId); Assert.Equal(ConnectionId, eventData.ConnectionId); Assert.Equal(_commandMethod, eventData.ExecuteMethod); + //Assert.Equal(_commandSource, eventData.CommandSource); ExecutedCalled = true; } @@ -1917,7 +1927,9 @@ protected virtual void AssertCreated(DbCommand command, CommandEndEventData even Assert.Equal(CommandId, eventData.CommandId); Assert.Equal(ConnectionId, eventData.ConnectionId); Assert.Equal(_commandMethod, eventData.ExecuteMethod); + //Assert.Equal(_commandSource, eventData.CommandSource); + CommandSource = eventData.CommandSource; CreatedCalled = true; } @@ -1928,8 +1940,10 @@ protected virtual void AssertFailed(DbCommand command, CommandErrorEventData eve Assert.Equal(CommandId, eventData.CommandId); Assert.Equal(ConnectionId, eventData.ConnectionId); Assert.Equal(_commandMethod, eventData.ExecuteMethod); + //Assert.Equal(_commandSource, eventData.CommandSource); Assert.NotNull(eventData.Exception); + CommandSource = eventData.CommandSource; Exception = eventData.Exception; FailedCalled = true; } diff --git a/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs b/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs index c38f0978ae6..a78a4186cc7 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs @@ -21,7 +21,8 @@ public InterceptionResult CommandCreating( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) => default; public DbCommand CommandCreated( @@ -32,6 +33,7 @@ public DbCommand CommandCreated( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) => command; @@ -41,7 +43,8 @@ public InterceptionResult CommandReaderExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) => default; public InterceptionResult CommandScalarExecuting( @@ -50,7 +53,8 @@ public InterceptionResult CommandScalarExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) => default; /// @@ -62,6 +66,7 @@ public InterceptionResult CommandScalarExecuting( /// The correlation ID associated with the given . /// The correlation ID associated with the being used. /// The time that execution began. + /// Source of the command. /// An intercepted result. public InterceptionResult CommandNonQueryExecuting( IRelationalConnection connection, @@ -69,7 +74,8 @@ public InterceptionResult CommandNonQueryExecuting( DbContext? context, Guid commandId, Guid connectionId, - DateTimeOffset startTime) + DateTimeOffset startTime, + CommandSource commandSource) => default; public ValueTask> CommandReaderExecutingAsync( @@ -79,6 +85,7 @@ public ValueTask> CommandReaderExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) => default; @@ -89,6 +96,7 @@ public ValueTask> CommandScalarExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) => default; @@ -99,6 +107,7 @@ public ValueTask> CommandNonQueryExecutingAsync( Guid commandId, Guid connectionId, DateTimeOffset startTime, + CommandSource commandSource, CancellationToken cancellationToken = default) => default; @@ -110,6 +119,7 @@ public DbDataReader CommandReaderExecuted( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) => methodResult; @@ -121,6 +131,7 @@ public DbDataReader CommandReaderExecuted( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) => methodResult; @@ -132,6 +143,7 @@ public int CommandNonQueryExecuted( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) => methodResult; @@ -143,6 +155,7 @@ public ValueTask CommandReaderExecutedAsync( Guid connectionId, DbDataReader methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) => new(methodResult); @@ -155,6 +168,7 @@ public ValueTask CommandReaderExecutedAsync( Guid connectionId, object? methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) => new(methodResult); @@ -167,6 +181,7 @@ public ValueTask CommandNonQueryExecutedAsync( Guid connectionId, int methodResult, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) => new(methodResult); @@ -180,6 +195,7 @@ public void CommandError( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration) { } @@ -193,6 +209,7 @@ public Task CommandErrorAsync( Guid connectionId, Exception exception, DateTimeOffset startTime, + CommandSource commandSource, TimeSpan duration, CancellationToken cancellationToken = default) => Task.CompletedTask; diff --git a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs index 96947141764..476b9c303cc 100644 --- a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs +++ b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestRelationalCommandBuilderFactory.cs @@ -125,7 +125,7 @@ public int ExecuteNonQuery(RelationalCommandParameterObject parameterObject) public Task ExecuteNonQueryAsync( RelationalCommandParameterObject parameterObject, - CancellationToken cancellationToken = new()) + CancellationToken cancellationToken = default) { var connection = parameterObject.Connection; var errorNumber = PreExecution(connection); @@ -157,7 +157,7 @@ public object ExecuteScalar(RelationalCommandParameterObject parameterObject) public async Task ExecuteScalarAsync( RelationalCommandParameterObject parameterObject, - CancellationToken cancellationToken = new()) + CancellationToken cancellationToken = default) { var connection = parameterObject.Connection; var errorNumber = PreExecution(connection); @@ -190,12 +190,12 @@ public RelationalDataReader ExecuteReader(RelationalCommandParameterObject param public async Task ExecuteReaderAsync( RelationalCommandParameterObject parameterObject, - CancellationToken cancellationToken = new()) + CancellationToken cancellationToken = default) { var connection = parameterObject.Connection; var errorNumber = PreExecution(connection); - var result = await _realRelationalCommand.ExecuteReaderAsync(parameterObject, cancellationToken); + var result = await _realRelationalCommand.ExecuteReaderAsync(parameterObject); if (errorNumber.HasValue) { connection.DbConnection.Close(); @@ -206,7 +206,10 @@ public async Task ExecuteReaderAsync( return result; } - public DbCommand CreateDbCommand(RelationalCommandParameterObject parameterObject, Guid commandId, DbCommandMethod commandMethod) + public DbCommand CreateDbCommand( + RelationalCommandParameterObject parameterObject, + Guid commandId, + DbCommandMethod commandMethod) => throw new NotSupportedException(); public void PopulateFrom(IRelationalCommand command) diff --git a/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs b/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs index 57777d44032..cc1b743926b 100644 --- a/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs +++ b/test/EFCore.SqlServer.Tests/SqlServerDatabaseCreatorTest.cs @@ -282,7 +282,10 @@ public Task ExecuteReaderAsync( CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public DbCommand CreateDbCommand(RelationalCommandParameterObject parameterObject, Guid commandId, DbCommandMethod commandMethod) + public DbCommand CreateDbCommand( + RelationalCommandParameterObject parameterObject, + Guid commandId, + DbCommandMethod commandMethod) => throw new NotImplementedException(); public object ExecuteScalar(RelationalCommandParameterObject parameterObject) diff --git a/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs b/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs index 1d64e8fd8e6..b1f91945993 100644 --- a/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs +++ b/test/EFCore.SqlServer.Tests/SqlServerSequenceValueGeneratorTest.cs @@ -278,7 +278,10 @@ public Task ExecuteReaderAsync( throw new NotImplementedException(); } - public DbCommand CreateDbCommand(RelationalCommandParameterObject parameterObject, Guid commandId, DbCommandMethod commandMethod) + public DbCommand CreateDbCommand( + RelationalCommandParameterObject parameterObject, + Guid commandId, + DbCommandMethod commandMethod) => throw new NotImplementedException(); public void PopulateFrom(IRelationalCommand command) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/BadDataSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/BadDataSqliteTest.cs index d2c659822db..e305911027b 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/BadDataSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/BadDataSqliteTest.cs @@ -169,7 +169,8 @@ public BadDataRelationalCommand( _values = values; } - public override RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject) + public override RelationalDataReader ExecuteReader( + RelationalCommandParameterObject parameterObject) { var command = parameterObject.Connection.DbConnection.CreateCommand(); command.CommandText = CommandText;