Registrazione e intercettazione delle operazioni di databaseLogging and intercepting database operations

Nota

Solo EF6 e versioni successive: funzionalità, API e altri argomenti discussi in questa pagina sono stati introdotti in Entity Framework 6.EF6 Onwards Only - The features, APIs, etc. discussed in this page were introduced in Entity Framework 6. Se si usa una versione precedente, le informazioni qui riportate, o parte di esse, non sono applicabili.If you are using an earlier version, some or all of the information does not apply.

A partire da Entity Framework 6, in qualsiasi momento Entity Framework invia un comando al database, questo comando può essere intercettato dal codice dell'applicazione.Starting with Entity Framework 6, anytime Entity Framework sends a command to the database this command can be intercepted by application code. Questa operazione viene usata più di frequente per la registrazione di SQL, ma può essere usata anche per modificare o interrompere il comando.This is most commonly used for logging SQL, but can also be used to modify or abort the command.

In particolare, EF include:Specifically, EF includes:

  • Proprietà di log per il contesto simile a DataContext. log in LINQ to SQLA Log property for the context similar to DataContext.Log in LINQ to SQL
  • Meccanismo per personalizzare il contenuto e la formattazione dell'output inviato al logA mechanism to customize the content and formatting of the output sent to the log
  • Blocchi predefiniti di basso livello per l'intercettazione che offrono maggiore controllo/flessibilitàLow-level building blocks for interception giving greater control/flexibility

Proprietà log del contestoContext Log property

La proprietà DbContext. database. log può essere impostata su un delegato per qualsiasi metodo che accetta una stringa.The DbContext.Database.Log property can be set to a delegate for any method that takes a string. In genere viene usato con qualsiasi TextWriter impostando il metodo "Write" del TextWriter.Most commonly it is used with any TextWriter by setting it to the “Write” method of that TextWriter. Tutti i SQL generati dal contesto corrente verranno registrati nel writer.All SQL generated by the current context will be logged to that writer. Il codice seguente, ad esempio, registrerà SQL sulla console:For example, the following code will log SQL to the console:

using (var context = new BlogContext())
{
    context.Database.Log = Console.Write;

    // Your code here...
}

Si noti che context. Database. log è impostato su console. Write.Notice that context.Database.Log is set to Console.Write. Questo è tutto ciò che serve per accedere a SQL alla console.This is all that is needed to log SQL to the console.

È ora possibile aggiungere un semplice codice di query/inserimento/aggiornamento per visualizzare un output:Let’s add some simple query/insert/update code so that we can see some output:

using (var context = new BlogContext())
{
    context.Database.Log = Console.Write;

    var blog = context.Blogs.First(b => b.Title == "One Unicorn");

    blog.Posts.First().Title = "Green Eggs and Ham";

    blog.Posts.Add(new Post { Title = "I do not like them!" });

    context.SaveChangesAsync().Wait();
}

Verrà generato l'output seguente:This will generate the following output:

SELECT TOP (1)
    [Extent1].[Id] AS [Id],
    [Extent1].[Title] AS [Title]
    FROM [dbo].[Blogs] AS [Extent1]
    WHERE (N'One Unicorn' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 4 ms with result: SqlDataReader

SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[Title] AS [Title],
    [Extent1].[BlogId] AS [BlogId]
    FROM [dbo].[Posts] AS [Extent1]
    WHERE [Extent1].[BlogId] = @EntityKeyValue1
-- EntityKeyValue1: '1' (Type = Int32)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader

UPDATE [dbo].[Posts]
SET [Title] = @0
WHERE ([Id] = @1)
-- @0: 'Green Eggs and Ham' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 12 ms with result: 1

INSERT [dbo].[Posts]([Title], [BlogId])
VALUES (@0, @1)
SELECT [Id]
FROM [dbo].[Posts]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'I do not like them!' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader

Si noti che si tratta dell'output presumendo che sia già stata eseguita l'inizializzazione del database.(Note that this is the output assuming any database initialization has already happened. Se l'inizializzazione del database non è già stata eseguita, verrà visualizzato molto altro output che Mostra tutte le migrazioni di lavoro eseguite dietro le quinte per verificare o creare un nuovo database.If database initialization had not already happened then there would be a lot more output showing all the work Migrations does under the covers to check for or create a new database.)

Cosa viene registrato?What gets logged?

Quando viene impostata la proprietà log, verranno registrate tutte le operazioni seguenti:When the Log property is set all of the following will be logged:

  • SQL per tutti i diversi tipi di comandi.SQL for all different kinds of commands. Ad esempio:For example:
    • Query, incluse le query LINQ normali, le query eSQL e le query non elaborate da metodi come SQLQueryQueries, including normal LINQ queries, eSQL queries, and raw queries from methods such as SqlQuery
    • Inserimenti, aggiornamenti ed eliminazioni generate come parte di SaveChangesInserts, updates, and deletes generated as part of SaveChanges
    • Relazione che carica query come quelle generate dal caricamento lazyRelationship loading queries such as those generated by lazy loading
  • ParametriParameters
  • Indica se il comando viene eseguito in modo asincronoWhether or not the command is being executed asynchronously
  • Timestamp che indica quando è iniziata l'esecuzione del comandoA timestamp indicating when the command started executing
  • Indica se il comando è stato completato correttamente, non è riuscito generando un'eccezione oppure, per async, è stato annullatoWhether or not the command completed successfully, failed by throwing an exception, or, for async, was canceled
  • Indicazione del valore del risultatoSome indication of the result value
  • Quantità approssimativa di tempo impiegato per eseguire il comando.The approximate amount of time it took to execute the command. Si noti che questo è il tempo di invio del comando per ottenere nuovamente l'oggetto risultato.Note that this is the time from sending the command to getting the result object back. Non è incluso il tempo necessario per leggere i risultati.It does not include time to read the results.

Esaminando l'output di esempio precedente, ognuno dei quattro comandi registrati è:Looking at the example output above, each of the four commands logged are:

  • Query risultante dalla chiamata al contesto. Blog. primaThe query resulting from the call to context.Blogs.First
    • Si noti che il metodo ToString per ottenere SQL non funzionava per questa query perché "First" non fornisce un oggetto IQueryable su cui è possibile chiamare ToStringNotice that the ToString method of getting the SQL would not have worked for this query since “First” does not provide an IQueryable on which ToString could be called
  • Query risultante dal caricamento lazy del Blog. PostThe query resulting from the lazy-loading of blog.Posts
    • Si notino i dettagli del parametro per il valore della chiave per cui è in corso il caricamento lazyNotice the parameter details for the key value for which lazy loading is happening
    • Vengono registrate solo le proprietà del parametro impostate sui valori non predefiniti.Only properties of the parameter that are set to non-default values are logged. Ad esempio, la proprietà Size viene visualizzata solo se è diverso da zero.For example, the Size property is only shown if it is non-zero.
  • Due comandi risultanti da SaveChangesAsync; uno per l'aggiornamento per modificare un titolo post, l'altro per un inserimento per aggiungere un nuovo postTwo commands resulting from SaveChangesAsync; one for the update to change a post title, the other for an insert to add a new post
    • Si notino i dettagli del parametro per le proprietà FK e titleNotice the parameter details for the FK and Title properties
    • Si noti che questi comandi vengono eseguiti in modo asincronoNotice that these commands are being executed asynchronously

Registrazione in posizioni diverseLogging to different places

Come illustrato sopra, la registrazione alla console è molto semplice.As shown above logging to the console is super easy. È anche facile accedere a memoria, file e così via usando diversi tipi di TextWriterIt’s also easy to log to memory, file, etc. by using different kinds of TextWriter.

Se si ha familiarità con LINQ to SQL si può notare che in LINQ to SQL la proprietà log è impostata sull'oggetto TextWriter effettivo (ad esempio, console. out) mentre in EF la proprietà log è impostata su un metodo che accetta una stringa (ad esempio , Console. Write o console. out. Write).If you are familiar with LINQ to SQL you might notice that in LINQ to SQL the Log property is set to the actual TextWriter object (for example, Console.Out) while in EF the Log property is set to a method that accepts a string (for example, Console.Write or Console.Out.Write). Il motivo è quello di separare EF da TextWriter accettando qualsiasi delegato che può fungere da sink per le stringhe.The reason for this is to decouple EF from TextWriter by accepting any delegate that can act as a sink for strings. Si supponga, ad esempio, di avere già un Framework di registrazione e di definire un metodo di registrazione come il seguente:For example, imagine that you already have some logging framework and it defines a logging method like so:

public class MyLogger
{
    public void Log(string component, string message)
    {
        Console.WriteLine("Component: {0} Message: {1} ", component, message);
    }
}

Questa operazione può essere collegata alla proprietà del log EF in questo modo:This could be hooked up to the EF Log property like this:

var logger = new MyLogger();
context.Database.Log = s => logger.Log("EFApp", s);

Registrazione risultatiResult logging

Il logger predefinito registra il testo del comando (SQL), i parametri e la riga "in esecuzione" con un timestamp prima che il comando venga inviato al database.The default logger logs command text (SQL), parameters, and the “Executing” line with a timestamp before the command is sent to the database. Una riga "completata" che contiene il tempo trascorso viene registrata dopo l'esecuzione del comando.A “completed” line containing elapsed time is logged following execution of the command.

Si noti che per i comandi asincroni la riga "completata" non viene registrata fino a quando l'attività asincrona non viene effettivamente completata, non riesce o viene annullata.Note that for async commands the “completed” line is not logged until the async task actually completes, fails, or is canceled.

La riga "completata" contiene informazioni diverse a seconda del tipo di comando e se l'esecuzione ha avuto esito positivo o negativo.The “completed” line contains different information depending on the type of command and whether or not execution was successful.

Esecuzione completataSuccessful execution

Per i comandi che vengono completati correttamente, l'output è "completato in x ms con risultato:" seguito da un'indicazione del risultato.For commands that complete successfully the output is “Completed in x ms with result: “ followed by some indication of what the result was. Per i comandi che restituiscono un lettore di dati, l'indicazione del risultato è il tipo di DbDataReader restituito.For commands that return a data reader the result indication is the type of DbDataReader returned. Per i comandi che restituiscono un valore integer, ad esempio il comando Update illustrato sopra, il risultato visualizzato è tale integer.For commands that return an integer value such as the update command shown above the result shown is that integer.

Esecuzione non riuscitaFailed execution

Per i comandi che hanno esito negativo generando un'eccezione, l'output contiene il messaggio dell'eccezione.For commands that fail by throwing an exception, the output contains the message from the exception. Se ad esempio si usa sqlQuery per eseguire una query su una tabella esistente, l'output del log potrebbe essere simile al seguente:For example, using SqlQuery to query against a table that does exist will result in log output something like this:

SELECT * from ThisTableIsMissing
-- Executing at 5/13/2013 10:19:05 AM
-- Failed in 1 ms with error: Invalid object name 'ThisTableIsMissing'.

Esecuzione annullataCanceled execution

Per i comandi asincroni in cui l'attività viene annullata, il risultato potrebbe essere un errore con un'eccezione, poiché si tratta spesso del provider ADO.NET sottostante quando viene eseguito un tentativo di annullamento.For async commands where the task is canceled the result could be failure with an exception, since this is what the underlying ADO.NET provider often does when an attempt is made to cancel. Se questa operazione non viene eseguita e l'attività viene annullata in modo corretto, l'output sarà simile al seguente:If this doesn’t happen and the task is canceled cleanly then the output will look something like this:

update Blogs set Title = 'No' where Id = -1
-- Executing asynchronously at 5/13/2013 10:21:10 AM
-- Canceled in 1 ms

Modifica del contenuto e della formattazione del logChanging log content and formatting

In copre la proprietà database. log si avvale di un oggetto DatabaseLogFormatter.Under the covers the Database.Log property makes use of a DatabaseLogFormatter object. Questo oggetto associa efficacemente un'implementazione di IDbCommandInterceptor (vedere di seguito) a un delegato che accetta stringhe e un DbContext.This object effectively binds an IDbCommandInterceptor implementation (see below) to a delegate that accepts strings and a DbContext. Ciò significa che i metodi su DatabaseLogFormatter vengono chiamati prima e dopo l'esecuzione di comandi da EF.This means that methods on DatabaseLogFormatter are called before and after the execution of commands by EF. Questi metodi DatabaseLogFormatter raccolgono e formattano l'output del log e lo inviano al delegato.These DatabaseLogFormatter methods gather and format log output and send it to the delegate.

Personalizzazione di DatabaseLogFormatterCustomizing DatabaseLogFormatter

La modifica degli elementi registrati e della relativa formattazione può essere eseguita creando una nuova classe che deriva da DatabaseLogFormatter ed esegue l'override dei metodi in base alle esigenze.Changing what is logged and how it is formatted can be achieved by creating a new class that derives from DatabaseLogFormatter and overrides methods as appropriate. I metodi più comuni per eseguire l'override sono:The most common methods to override are:

  • LogCommand: esegue l'override di questo per modificare il modo in cui vengono registrati i comandi prima che vengano eseguiti.LogCommand – Override this to change how commands are logged before they are executed. Per impostazione predefinita, LogCommand chiama LogParameter per ogni parametro; è possibile scegliere di eseguire la stessa operazione in sostituzione o di gestire i parametri in modo diverso.By default LogCommand calls LogParameter for each parameter; you may choose to do the same in your override or handle parameters differently instead.
  • LogResult: esegue l'override di questo per modificare il modo in cui viene registrato il risultato dell'esecuzione di un comando.LogResult – Override this to change how the outcome from executing a command is logged.
  • LogParameter: esegue l'override di questo per modificare la formattazione e il contenuto della registrazione dei parametri.LogParameter – Override this to change the formatting and content of parameter logging.

Si supponga, ad esempio, di voler registrare solo una singola riga prima che ogni comando venga inviato al database.For example, suppose we wanted to log just a single line before each command is sent to the database. Questa operazione può essere eseguita con due sostituzioni:This can be done with two overrides:

  • Eseguire l'override di LogCommand per formattare e scrivere la riga singola di SQLOverride LogCommand to format and write the single line of SQL
  • Eseguire l'override di LogResult per non eseguire alcuna operazione.Override LogResult to do nothing.

Il codice avrà un aspetto simile al seguente:The code would look something like this:

public class OneLineFormatter : DatabaseLogFormatter
{
    public OneLineFormatter(DbContext context, Action<string> writeAction)
        : base(context, writeAction)
    {
    }

    public override void LogCommand<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        Write(string.Format(
            "Context '{0}' is executing command '{1}'{2}",
            Context.GetType().Name,
            command.CommandText.Replace(Environment.NewLine, ""),
            Environment.NewLine));
    }

    public override void LogResult<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
    }
}

Per registrare l'output, è sufficiente chiamare il metodo Write che invierà l'output al delegato di scrittura configurato.To log output simply call the Write method which will send output to the configured write delegate.

Si noti che questo codice consente di rimuovere semplicisticamente le interruzioni di riga solo come esempio.(Note that this code does simplistic removal of line breaks just as an example. Probabilmente non funzionerà correttamente per la visualizzazione di SQL complesso.It will likely not work well for viewing complex SQL.)

Impostazione di DatabaseLogFormatterSetting the DatabaseLogFormatter

Una volta creata una nuova classe DatabaseLogFormatter, è necessario registrarla con EF.Once a new DatabaseLogFormatter class has been created it needs to be registered with EF. Questa operazione viene eseguita usando la configurazione basata su codice.This is done using code-based configuration. In breve, ciò significa creare una nuova classe che deriva da DbConfiguration nello stesso assembly della classe DbContext e quindi chiamare SetDatabaseLogFormatter nel costruttore di questa nuova classe.In a nutshell this means creating a new class that derives from DbConfiguration in the same assembly as your DbContext class and then calling SetDatabaseLogFormatter in the constructor of this new class. Ad esempio:For example:

public class MyDbConfiguration : DbConfiguration
{
    public MyDbConfiguration()
    {
        SetDatabaseLogFormatter(
            (context, writeAction) => new OneLineFormatter(context, writeAction));
    }
}

Uso del nuovo DatabaseLogFormatterUsing the new DatabaseLogFormatter

Questo nuovo DatabaseLogFormatter verrà ora usato ogni volta che viene impostato database. log.This new DatabaseLogFormatter will now be used anytime Database.Log is set. In questo modo, l'esecuzione del codice dalla parte 1 determinerà l'output seguente:So, running the code from part 1 will now result in the following output:

Context 'BlogContext' is executing command 'SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title]FROM [dbo].[Blogs] AS [Extent1]WHERE (N'One Unicorn' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL)'
Context 'BlogContext' is executing command 'SELECT [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], [Extent1].[BlogId] AS [BlogId]FROM [dbo].[Posts] AS [Extent1]WHERE [Extent1].[BlogId] = @EntityKeyValue1'
Context 'BlogContext' is executing command 'update [dbo].[Posts]set [Title] = @0where ([Id] = @1)'
Context 'BlogContext' is executing command 'insert [dbo].[Posts]([Title], [BlogId])values (@0, @1)select [Id]from [dbo].[Posts]where @@rowcount > 0 and [Id] = scope_identity()'

Blocchi predefiniti di intercettazioneInterception building blocks

Fino a questo punto abbiamo esaminato come usare DbContext. database. log per registrare il database SQL generato da EF.So far we have looked at how to use DbContext.Database.Log to log the SQL generated by EF. Tuttavia, questo codice è in realtà una facciata relativamente sottile rispetto ad alcuni blocchi predefiniti di basso livello per un'intercettazione più generale.But this code is actually a relatively thin facade over some low-level building blocks for more general interception.

Interfacce di intercettazioneInterception interfaces

Il codice di intercettazione è basato sul concetto di interfacce di intercettazione.The interception code is built around the concept of interception interfaces. Queste interfacce ereditano da IDbInterceptor e definiscono metodi che vengono chiamati quando EF esegue un'azione.These interfaces inherit from IDbInterceptor and define methods that are called when EF performs some action. Lo scopo è quello di avere un'interfaccia per ogni tipo di oggetto intercettato.The intent is to have one interface per type of object being intercepted. Ad esempio, l'interfaccia IDbCommandInterceptor definisce i metodi che vengono chiamati prima che EF effettua una chiamata a ExecuteNonQuery, ExecuteScalar, ExecuteReader e ai metodi correlati.For example, the IDbCommandInterceptor interface defines methods that are called before EF makes a call to ExecuteNonQuery, ExecuteScalar, ExecuteReader, and related methods. Analogamente, l'interfaccia definisce i metodi che vengono chiamati al completamento di ciascuna di queste operazioni.Likewise, the interface defines methods that are called when each of these operations completes. La classe DatabaseLogFormatter esaminata in precedenza implementa questa interfaccia per registrare i comandi.The DatabaseLogFormatter class that we looked at above implements this interface to log commands.

Contesto di intercettazioneThe interception context

Osservando i metodi definiti in una delle interfacce dell'intercettore è evidente che a ogni chiamata viene assegnato un oggetto di tipo DbInterceptionContext o un tipo derivato da questo, ad esempio DbCommandInterceptionContext<>.Looking at the methods defined on any of the interceptor interfaces it is apparent that every call is given an object of type DbInterceptionContext or some type derived from this such as DbCommandInterceptionContext<>. Questo oggetto contiene informazioni contestuali sull'azione che EF sta assumendo.This object contains contextual information about the action that EF is taking. Se, ad esempio, l'azione viene eseguita per conto di un DbContext, il DbContext viene incluso nel DbInterceptionContext.For example, if the action is being taken on behalf of a DbContext, then the DbContext is included in the DbInterceptionContext. Analogamente, per i comandi eseguiti in modo asincrono, il flag asincrono viene impostato su DbCommandInterceptionContext.Similarly, for commands that are being executed asynchronously, the IsAsync flag is set on DbCommandInterceptionContext.

Gestione dei risultatiResult handling

La classe DbCommandInterceptionContext<> contiene le proprietà denominate result, OriginalResult, Exception e originalException.The DbCommandInterceptionContext<> class contains a properties called Result, OriginalResult, Exception, and OriginalException. Queste proprietà vengono impostate su null/zero per le chiamate ai metodi di intercettazione che vengono chiamate prima dell'esecuzione dell'operazione, ovvero per... Esecuzione di metodi.These properties are set to null/zero for calls to the interception methods that are called before the operation is executed — that is, for the …Executing methods. Se l'operazione viene eseguita e ha esito positivo, result e OriginalResult vengono impostati sul risultato dell'operazione.If the operation is executed and succeeds, then Result and OriginalResult are set to the result of the operation. Questi valori possono quindi essere osservati nei metodi di intercettazione che vengono chiamati dopo l'esecuzione dell'operazione, ovvero sul... Metodi eseguiti.These values can then be observed in the interception methods that are called after the operation has executed — that is, on the …Executed methods. Analogamente, se l'operazione genera, verranno impostate le proprietà Exception e originalException.Likewise, if the operation throws, then the Exception and OriginalException properties will be set.

Eliminazione dell'esecuzioneSuppressing execution

Se un intercettore imposta la proprietà Result prima dell'esecuzione del comando (in uno dei... Eseguendo metodi), EF non tenterà di eseguire effettivamente il comando, ma userà invece il set di risultati.If an interceptor sets the Result property before the command has executed (in one of the …Executing methods) then EF will not attempt to actually execute the command, but will instead just use the result set. In altre parole, l'intercettore può impedire l'esecuzione del comando, ma EF continua come se il comando fosse stato eseguito.In other words, the interceptor can suppress execution of the command but have EF continue as if the command had been executed.

Un esempio di come questa operazione può essere utilizzata è il batch dei comandi che è stato tradizionalmente eseguito con un provider di wrapping.An example of how this might be used is the command batching that has traditionally been done with a wrapping provider. L'intercettore archivia il comando per un'esecuzione successiva come batch, ma "finge" per EF che il comando è stato eseguito normalmente.The interceptor would store the command for later execution as a batch but would “pretend” to EF that the command had executed as normal. Si noti che questa operazione richiede più di questo per implementare l'invio in batch, ma questo è un esempio di come è possibile usare la modifica del risultato dell'intercettazione.Note that it requires more than this to implement batching, but this is an example of how changing the interception result might be used.

L'esecuzione può anche essere eliminata impostando la proprietà Exception in uno dei... Esecuzione di metodi.Execution can also be suppressed by setting the Exception property in one of the …Executing methods. Questo fa sì che EF continui come se l'esecuzione dell'operazione non fosse riuscita generando l'eccezione specificata.This causes EF to continue as if execution of the operation had failed by throwing the given exception. Questo può, ovviamente, causare l'arresto anomalo dell'applicazione, ma potrebbe anche essere un'eccezione temporanea o un'altra eccezione gestita da EF.This may, of course, cause the application to crash, but it may also be a transient exception or some other exception that is handled by EF. Ad esempio, questo può essere usato negli ambienti di test per testare il comportamento di un'applicazione quando l'esecuzione del comando ha esito negativo.For example, this could be used in test environments to test the behavior of an application when command execution fails.

Modifica del risultato dopo l'esecuzioneChanging the result after execution

Se un intercettore imposta la proprietà Result dopo l'esecuzione del comando (in uno dei... Metodi eseguiti), EF utilizzerà il risultato modificato anziché il risultato effettivamente restituito dall'operazione.If an interceptor sets the Result property after the command has executed (in one of the …Executed methods) then EF will use the changed result instead of the result that was actually returned from the operation. Analogamente, se un intercettore imposta la proprietà Exception dopo l'esecuzione del comando, EF genererà l'eccezione set come se l'operazione avesse generato l'eccezione.Similarly, if an interceptor sets the Exception property after the command has executed, then EF will throw the set exception as if the operation had thrown the exception.

Un intercettore può inoltre impostare la proprietà Exception su null per indicare che non deve essere generata alcuna eccezione.An interceptor can also set the Exception property to null to indicate that no exception should be thrown. Questo può essere utile se l'esecuzione dell'operazione non è riuscita, ma l'intercettore desidera che EF continui come se l'operazione avesse avuto esito positivo.This can be useful if execution of the operation failed but the interceptor wishes EF to continue as if the operation had succeeded. Questa operazione comporta in genere anche l'impostazione del risultato, in modo che Entity Framework abbia un valore di risultato da usare come continuerà.This usually also involves setting the Result so that EF has some result value to work with as it continues.

OriginalResult ed OriginalExceptionOriginalResult and OriginalException

Dopo l'esecuzione di un'operazione da parte di EF, verranno impostate le proprietà Result e OriginalResult se l'esecuzione non ha esito negativo oppure le proprietà Exception e originalException se l'esecuzione non è riuscita con un'eccezione.After EF has executed an operation it will set either the Result and OriginalResult properties if execution did not fail or the Exception and OriginalException properties if execution failed with an exception.

Le proprietà OriginalResult e originalException sono di sola lettura e vengono impostate solo da EF dopo l'esecuzione effettiva di un'operazione.The OriginalResult and OriginalException properties are read-only and are only set by EF after actually executing an operation. Queste proprietà non possono essere impostate dagli intercettori.These properties cannot be set by interceptors. Ciò significa che qualsiasi intercettore può distinguere tra un'eccezione o un risultato che è stato impostato da un altro intercettore anziché l'eccezione reale o il risultato che si è verificato durante l'esecuzione dell'operazione.This means that any interceptor can distinguish between an exception or result that has been set by some other interceptor as opposed to the real exception or result that occurred when the operation was executed.

Registrazione degli intercettoriRegistering interceptors

Quando una classe che implementa una o più interfacce di intercettazione è stata creata, può essere registrata con EF usando la classe DbInterception.Once a class that implements one or more of the interception interfaces has been created it can be registered with EF using the DbInterception class. Ad esempio:For example:

DbInterception.Add(new NLogCommandInterceptor());

Gli intercettori possono essere registrati anche a livello di dominio dell'applicazione usando il meccanismo di configurazione basato sul codice DbConfiguration.Interceptors can also be registered at the app-domain level using the DbConfiguration code-based configuration mechanism.

Esempio: registrazione in NLogExample: Logging to NLog

È necessario riunirle in un esempio che usa IDbCommandInterceptor e NLog per:Let’s put all this together into an example that using IDbCommandInterceptor and NLog to:

  • Registra un avviso per qualsiasi comando eseguito in modo non asincronoLog a warning for any command that is executed non-asynchronously
  • Registra un errore per qualsiasi comando che genera un'eccezione durante l'esecuzioneLog an error for any command that throws when executed

Ecco la classe che esegue la registrazione, che deve essere registrata come illustrato in precedenza:Here’s the class that does the logging, which should be registered as shown above:

public class NLogCommandInterceptor : IDbCommandInterceptor
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    public void NonQueryExecuting(
        DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void NonQueryExecuted(
        DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }

    public void ReaderExecuting(
        DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void ReaderExecuted(
        DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }

    public void ScalarExecuting(
        DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        LogIfNonAsync(command, interceptionContext);
    }

    public void ScalarExecuted(
        DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        LogIfError(command, interceptionContext);
    }

    private void LogIfNonAsync<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        if (!interceptionContext.IsAsync)
        {
            Logger.Warn("Non-async command used: {0}", command.CommandText);
        }
    }

    private void LogIfError<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        if (interceptionContext.Exception != null)
        {
            Logger.Error("Command {0} failed with exception {1}",
                command.CommandText, interceptionContext.Exception);
        }
    }
}

Si noti che questo codice usa il contesto di intercettazione per individuare quando un comando viene eseguito in modo non asincrono e per individuare quando si è verificato un errore durante l'esecuzione di un comando.Notice how this code uses the interception context to discover when a command is being executed non-asynchronously and to discover when there was an error executing a command.