Registrazione e l'intercettazione di 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, ogni volta che Entity Framework comando viene inviato un comando nel database possono essere intercettati 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. Viene in genere utilizzato per l'accesso SQL, ma può anche essere utilizzato 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, Entity Framework include:Specifically, EF includes:

  • Una 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
  • Un meccanismo per personalizzare la formattazione dell'output inviato al RegistroA mechanism to customize the content and formatting of the output sent to the log
  • Blocchi predefiniti di basso livello per l'intercettazione consente una maggiore flessibilità di controllo /Low-level building blocks for interception giving greater control/flexibility

Proprietà di contesto del LogContext 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 utilizzato con qualsiasi TextWriter impostandolo sul metodo di "Scrittura" di tale oggetto TextWriter.Most commonly it is used with any TextWriter by setting it to the “Write” method of that TextWriter. Tutti i SQL generato dal contesto corrente verrà registrato in tale writer.All SQL generated by the current context will be logged to that writer. Ad esempio, il codice seguente registrerà SQL nella 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 tale contesto. Database. log è impostato su console. Write.Notice that context.Database.Log is set to Console.Write. Questo è tutto ciò che è necessaria per l'accesso SQL nella console.This is all that is needed to log SQL to the console.

Aggiungere un semplice codice di aggiornamento/inserimento/query in modo che possiamo vedere alcuni 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 questo è l'output presupponendo che le operazioni di inizializzazione del database è già verificato.(Note that this is the output assuming any database initialization has already happened. Se l'inizializzazione del database non era già verificato, vi sarà molto più output che mostra tutte le operazioni migrazioni non dietro le quinte per cercare 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.)

Ciò che viene registrato?What gets logged?

Viene registrata quando è impostata la proprietà del Log di tutti gli elementi 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, query eSQL e query non elaborate dai metodi, ad esempio SqlQueryQueries, including normal LINQ queries, eSQL queries, and raw queries from methods such as SqlQuery
    • Gli inserimenti, aggiornamenti ed eliminazioni generate come parte del metodo SaveChangesInserts, updates, and deletes generated as part of SaveChanges
    • Relazioni caricano query, ad esempio quelli generati dal caricamento lazyRelationship loading queries such as those generated by lazy loading
  • ParametriParameters
  • Se viene eseguito in modo asincrono il comandoWhether or not the command is being executed asynchronously
  • Un timestamp che indica quando il comando avviato l'esecuzioneA timestamp indicating when the command started executing
  • Se il comando completato correttamente, non è riuscita generando un'eccezione o, per async, è stata annullataWhether or not the command completed successfully, failed by throwing an exception, or, for async, was canceled
  • Alcune indicazioni del valore del risultatoSome indication of the result value
  • La quantità approssimativa del tempo che necessario per eseguire il comando.The approximate amount of time it took to execute the command. Si noti che questo è il tempo dall'invio del comando per ottenere l'oggetto del risultato.Note that this is the time from sending the command to getting the result object back. Non include il tempo per leggere i risultati.It does not include time to read the results.

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

  • La query risultante dalla chiamata al contesto. Blogs.FirstThe query resulting from the call to context.Blogs.First
    • Si noti che il metodo ToString dell'introduzione di SQL non avrebbero funzionato per questa query perché "First" non è incluso un oggetto IQueryable su cui 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
  • La query risultante dal caricamento lazy di blog. PostThe query resulting from the lazy-loading of blog.Posts
    • Si noti che i dettagli dei parametri per il valore della chiave per cui il caricamento lazy è in corsoNotice the parameter details for the key value for which lazy loading is happening
    • Vengono registrate solo le proprietà del parametro che sono impostate su valori non predefiniti.Only properties of the parameter that are set to non-default values are logged. Ad esempio, la proprietà dimensioni solo viene visualizzata se è diverso da zero.For example, the Size property is only shown if it is non-zero.
  • Due comandi risultanti da SaveChangesAsync; una per l'aggiornamento modificare un titolo di post, l'altro per un'operazione di inserimento 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 noti che i dettagli dei parametri per le proprietà di chiave esterna e il titoloNotice 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 in precedenza la registrazione per la console è estremamente facile.As shown above logging to the console is super easy. È inoltre facile accedere alla memoria, file e così via usando diversi tipi di TextWriter.It’s also easy to log to memory, file, etc. by using different kinds of TextWriter.

Se si ha familiarità con LINQ to SQL è possibile notare che in LINQ to SQL con la proprietà di Log è impostata su TextWriter oggetto effettivo (ad esempio, console. Out) mentre in Entity Framework è impostata la proprietà del Log a un metodo che accetta una stringa (ad esempio 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 è separare EF da TextWriter mediante l'accettazione di un delegato che può agire come un 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. Ad esempio, si supponga che si dispone già di alcuni framework di registrazione e definisce un metodo di registrazione come illustrato di seguito: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);
    }
}

Ciò può essere associata a proprietà EF Log simile al seguente: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), parametri e la riga "Executing" con un timestamp prima il comando viene 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 è connesso seguendo 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 è connesso fino a quando l'attività asincrona in realtà viene completata, ha esito negativo o viene annullato.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 indica se l'esecuzione è stata completata.The “completed” line contains different information depending on the type of command and whether or not execution was successful.

Il completamento dell'esecuzioneSuccessful execution

Per i comandi che completano correttamente l'output è "completato in x ms con risultato:" seguita da alcune indicazioni relative Qual era il 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 il risultato di un lettore dati indicazione è il tipo della 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 l'aggiornamento comando illustrato in precedenza il risultato visualizzato è 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 non soddisfano 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. Ad esempio, uso SqlQuery per query su una tabella esistente verrà risultato nel registro output 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 di provider ADO.NET sottostante spesso funzionamento quando viene effettuato 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 ciò non accade e l'attività viene annullata normalmente quindi l'output avrà un aspetto 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

Impostazione del contenuto dei log e la formattazioneChanging log content and formatting

Dietro le quinte il database. log proprietà rende l'utilizzo di un oggetto DatabaseLogFormatter.Under the covers the Database.Log property makes use of a DatabaseLogFormatter object. Questo oggetto associa in modo efficace un'implementazione IDbCommandInterceptor (vedere sotto) a un delegato che accetta stringhe e un oggetto DbContext.This object effectively binds an IDbCommandInterceptor implementation (see below) to a delegate that accepts strings and a DbContext. Ciò significa che in DatabaseLogFormatter vengono chiamati prima e dopo l'esecuzione di comandi da Entity Framework.This means that methods on DatabaseLogFormatter are called before and after the execution of commands by EF. Questi metodi DatabaseLogFormatter raccogliere e formattare l'output di log e inviarlo al delegato.These DatabaseLogFormatter methods gather and format log output and send it to the delegate.

Personalizzazione DatabaseLogFormatterCustomizing DatabaseLogFormatter

Modificando ciò che viene registrato e come viene formattato può essere ottenuto creando una nuova classe che deriva da DatabaseLogFormatter e sovrascrive i metodi appropriati.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: eseguire l'Override di questa opzione per cambiare modalità di registrazione comandi prima che vengano eseguite.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 nell'override o gestire parametri invece 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: eseguire l'Override per modificare la modalità in cui è connesso il risultato dall'esecuzione di un comando.LogResult – Override this to change how the outcome from executing a command is logged.
  • LogParameter: eseguire l'Override per modificare la formattazione e il contenuto della registrazione di parametro.LogParameter – Override this to change the formatting and content of parameter logging.

Ad esempio, di voler accedere un'unica riga prima di ogni comando viene 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 LogCommand per formattare e scrivere la riga singola di SQLOverride LogCommand to format and write the single line of SQL
  • Eseguire l'override LogResult per non eseguire alcuna operazione.Override LogResult to do nothing.

Il codice sarebbe 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 semplicemente chiamare il metodo di scrittura che invia output al delegato scrittura configurata.To log output simply call the Write method which will send output to the configured write delegate.

(Si noti che questo codice esegue semplicistico per la rimozione di 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 istruzioni SQL complesse.)It will likely not work well for viewing complex SQL.)

Impostazione di DatabaseLogFormatterSetting the DatabaseLogFormatter

Dopo aver creata una nuova classe DatabaseLogFormatter deve essere registrata con Entity Framework.Once a new DatabaseLogFormatter class has been created it needs to be registered with EF. Questa operazione viene eseguita utilizzando la configurazione basata su codice.This is done using code-based configuration. In poche parole, ciò significa creare una nuova classe che deriva da DbConfiguration nello stesso assembly come la classe DbContext e chiamando quindi 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));
    }
}

Usando il nuovo DatabaseLogFormatterUsing the new DatabaseLogFormatter

Questo nuovo DatabaseLogFormatter ora essere usato ogni volta che viene impostato database. log.This new DatabaseLogFormatter will now be used anytime Database.Log is set. Quindi, eseguire il codice della parte 1 ora genererà 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

Finora abbiamo esaminato come utilizzare DbContext.Database.Log per registrare il codice SQL generato da Entity Framework.So far we have looked at how to use DbContext.Database.Log to log the SQL generated by EF. Ma questo codice è effettivamente una facciata relativamente thin su alcuni blocchi predefiniti di basso livello per l'intercettazione più generale.But this code is actually a relatively thin façade 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 di ereditano da IDbInterceptor e definiscono i metodi che vengono chiamati quando Entity Framework esegue una determinata azione.These interfaces inherit from IDbInterceptor and define methods that are called when EF performs some action. Si desidera 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 EF effettua una chiamata a metodi correlati, ExecuteReader, ExecuteScalar ed ExecuteNonQuery.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 ognuna di queste operazioni.Likewise, the interface defines methods that are called when each of these operations completes. La classe DatabaseLogFormatter che abbiamo visto in precedenza implementa questa interfaccia per registrare i comandi.The DatabaseLogFormatter class that we looked at above implements this interface to log commands.

Il contesto di intercettazioneThe interception context

Osservando i metodi definiti in una delle interfacce degli intercettori, è evidente che ogni chiamata è dato un oggetto di tipo DbInterceptionContext o un tipo derivato da questo oggetto, 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 relativi all'azione che richiede di Entity Framework.This object contains contextual information about the action that EF is taking. Ad esempio, se viene intrapresa l'azione per conto di un oggetto DbContext, DbContext è 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 che vengono eseguiti in modo asincrono, il flag IsAsync è nastavit DbCommandInterceptionContext.Similarly, for commands that are being executed asynchronously, the IsAsync flag is set on DbCommandInterceptionContext.

Gestione di risultatiResult handling

Il DbCommandInterceptionContext< > classe contiene una proprietà denominata risultati, OriginalResult, eccezioni 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 che vengono chiamati prima che l'operazione viene eseguita l'intercettazione, vale a dire, per il... Esecuzione dei 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, quindi risultato e OriginalResult vengono impostate 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 nel metodo di intercettazione che viene chiamati dopo che è stata eseguita l'operazione, vale a dire nel... 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, quindi le proprietà di eccezione e OriginalException verranno impostate.Likewise, if the operation throws, then the Exception and OriginalException properties will be set.

Eliminazione di esecuzioneSuppressing execution

Se un intercettore imposta la proprietà Result prima ha eseguito il comando (in uno di... Esecuzione di metodi) quindi Entity Framework non tenta di eseguire effettivamente il comando, ma verrà usato invece solo 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ò eliminare l'esecuzione del comando ma EF continua come se fosse stato eseguito il comando.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 ciò è possibile usare è il comando batch che è stati condotti in genere con un provider di ritorno a capo.An example of how this might be used is the command batching that has traditionally been done with a wrapping provider. L'intercettore sarebbe per memorizzare il comando per un'esecuzione successiva come batch, ma sarebbe "fingono" di Entity Framework che ha eseguito il comando come di consueto.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 richiede più di ciò per implementare l'invio in batch, ma questo è un esempio di come modificare il risultato di intercettazione è possibile usare.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ò essere evitata impostando la proprietà di eccezione in uno del... Esecuzione dei metodi.Execution can also be suppressed by setting the Exception property in one of the …Executing methods. Ciò fa sì che EF continuare come se l'esecuzione dell'operazione non è riuscito generando l'eccezione specificata.This causes EF to continue as if execution of the operation had failed by throwing the given exception. Ciò, naturalmente, potrebbe essere l'applicazione in modo anomalo, ma potrebbe anche essere un'eccezione temporanea o un'altra eccezione che viene gestita da Entity Framework.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, ciò potrebbe utilizzabile in 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.

Modificare il risultato dopo l'esecuzioneChanging the result after execution

Se un intercettore imposta la proprietà del risultato dopo avere eseguito il comando (in uno di... Eseguire i metodi) Entity Framework userà il risultato modificato anziché il risultato che è stata 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à di eccezione dopo avere eseguito il comando, quindi Entity Framework genererà l'eccezione di set come se l'operazione ha 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ò anche impostare la proprietà dell'eccezione su null per indicare che deve essere generata alcuna eccezione.An interceptor can also set the Exception property to null to indicate that no exception should be thrown. Ciò può essere utile se l'esecuzione dell'operazione non riuscita, ma l'intercettore intenda continuare come se l'operazione ha avuto esito positivo a Entity Framework.This can be useful if execution of the operation failed but the interceptor wishes EF to continue as if the operation had succeeded. Ciò comporta in genere anche impostando il risultato in modo che Entity Framework ha un valore di risultato per lavorare con man mano che continuano.This usually also involves setting the Result so that EF has some result value to work with as it continues.

OriginalResult e OriginalExceptionOriginalResult and OriginalException

Dopo avere eseguito un'operazione di Entity Framework imposta le proprietà di risultato e OriginalResult se l'esecuzione ha avuto esito positivo o le proprietà di eccezione 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.

La proprietà OriginalResult e OriginalException sono di sola lettura e vengono impostate solo da Entity Framework dopo effettivamente l'esecuzione 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 un'eccezione o un risultato che è stata impostata da alcuni altri intercettore anziché l'eccezione reale o un risultato che si è verificato durante l'operazione è stata eseguita.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.

La registrazione degli intercettoriRegistering interceptors

Dopo aver creata una classe che implementa uno o più delle interfacce di intercettazione può essere registrato con Entity Framework 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 a livello di dominio 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: La registrazione NLogExample: Logging to NLog

È possibile inserire tutte queste insieme in un esempio che l'utilizzo 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 che viene eseguito in modalità non asincronaLog a warning for any command that is executed non-asynchronously
  • Registrare un errore per qualsiasi comando che genera un'eccezione quando eseguitaLog an error for any command that throws when executed

Questa è 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 come questo codice Usa il contesto di intercettazione per rilevare quando un comando viene eseguito in modo non asincrono e per scoprire 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.