posts - 315, comments - 268, trackbacks - 15

My Links

News

View Pietro Libro's profile on LinkedIn

DomusDotNet
   DomusDotNet

Pietro Libro

Tag Cloud

Article Categories

Archives

Post Categories

Blogs amici

Links

EF 6 : Logging & Interception

 

Una delle nuove feature introdotte nella versione 6 di Entity Framework (attualmente in RC) è il supporto al logging dell’SQL generato dal runtime di EF6. A tal fine è sufficiente passare un opportuno delegate alla proporietà Log esposta da DbContext.Database. Per gli esempi riprendiamo lo scenario del post precedente.

Supponiamo di avere il seguente codice:

 using (CarContext db = new CarContext())
{
 
    System.Console.WriteLine("Cars in database : {0}", db.Cars.Count());

    ////Add a new car.
    Car car = new Car()
    {
        Brand = "Alfa Romeo",
        Model = "Giulietta"
    };

    db.Cars.Add(car);
    db.SaveChanges();

    System.Console.WriteLine("Cars in database : {0}", db.Cars.Count());               
}

Che banalmente visualizza il numero di auto (Cars) presenti nel  repository, ne aggiunge una e riesegue la conta delle auto registrate. Se volessimo analizzare l’SQL generato un ottimo strumento è sicuramete il SQL Profiler di SQL Server (che non dovrebbe mai mancare quando si lavora con un ORM Smile ), ma se utilizziamo EF6, ed il nostro obiettivo è semplicemente “scoprire\loggare” l’SQL generato da EF, possiamo modificare il codice precedente aggiungendo dopo la definizione del DbContext, la riga seguente:

 db.Database.Log = Console.Write;
 

Dove la proprietà Log è cosi’ definita:

public Action<string> Log { get; set; }
 

Eseguendo il codice della nostra applicazione dovremmo ottenere una “Console” simile alla seguente:

image

Di default il log è molto chiaro in quanto ci restituisce il testo SQL del comando, quando è stato eseguito, il tempo impiegato, il tipo di risultato, gli eventuali parametri ed il tipo corrispondente. Possiamo ovviamente cambiare il contenuto e la formattazione del log secondo le nostre esigenze (e non solo) come vedremo piu’ avanti. Per come è definita la proprietà Log, qualsiasi funzione che accetta una stringa puo’ essere utilizzata per scrivere il nostro log. Quindi potremmo utilizzare un metodo tipo il seguente:

public static void Log(string sql)
{
    Console.WriteLine("------------------------------------");
    Console.WriteLine("SQL LOG: {0} ", sql);
    Console.WriteLine("------------------------------------");            
}

 

oppure:

System.IO.StreamWriter streamWriter = new System.IO.StreamWriter (fileStream, System.Text.ASCIIEncoding.ASCII );
db.Database.Log = sql => streamWriter.Write(sql);

 

Per scrivere il log direttamente su file. Il concetto dovrebbe essere abbastanza chiaro. Vediamo come personalizzare la formattazione del log.

Database.Log non fa altro che utilizzare un ogetto DatabaseLogFormatter che a sua volta implementa le interfacce IDbCommandInterceptor e IDbInterceptor che sono rispettivamente l’interfaccia che permette di registrare un oggetto che possa ricevere notifiche da parte di Entity Framework quando un comando viene eseguito e l’interfaccia base per tutte le interfacce che permettono di fornire un Interception Point per differenti tipi di operazione.

image

Quindi, per creare il nostro “Formattatore Custom” non ci resta che ereditare dalla classe DatabaseLogFormatter ed eseguire l’override dei metodi che ci interessano, come nel caso seguente:

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

    public override void LogCommand<TResult>(
        DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
    {
        Write(string.Format("{0}{1}", "===============================================", Environment.NewLine));

        Write(string.Format(
            "Context{2}{0}{2}Command{2}{1}{2}",
            Context.GetType().Name,
            command.CommandText.Replace(Environment.NewLine, ""),
            Environment.NewLine));

        Write(string.Format("{0}{1}", "===============================================", Environment.NewLine));            
    }
}

 

Dove, l’override del metodo LogCommand esegue la formattazione del comando prima che questo sia eseguito da Entity Framework. LogCommand a sua volta  chiama eventualmente il metodo LogParameter per ogni parametro del comando, è necessario eseguire l’override di LogParameter per “customizzare” la formattazione del log dei paramateri. Infine, se vogliamo cambiare la formattazione del risultato, è necessario effettuare l’override di LogResult. Per interrompere l’esecuzione del comando, possiamo utilizzare il metodo :

interceptionContext.SuppressExecution()
 

Nel corpo dell’override di LogCommand. Per vedere in “funzione” il nostro “Formatter” è sufficiente registrare l’istanza di CustomLogFormatter tramite una classe derivata da DbConfiguration presente nello stesso assembly che contiene la definizione del DbContext:

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

Eseguendo, otteniamo il “nostro” log:

image

Per approfondimenti:

Entity Framework Codeplex

One Unicorn: EF6 SQL Logging

Print | posted on mercoledì 4 settembre 2013 17:15 | Filed Under [ C# SQL .Net Framework 4.0 SQL Server .Net Framework 4.5 Entity Framework 6 ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET