EF4 SQL Abfragen anzeigen für ObjectContext & DbContext


Wer häufig mit dem Entity Framework arbeitet kommt doch hin und wieder mal in die Verlegenheit und möchte gern wissen welche SQL Abfrage hier genau an den Server gesendet wurde. Wenn man hier nicht stolzer Besitzer eines Visual Studios Ultimate mit Intellitrace ist, muss man sich auf andere Weiße weiterhelfen.

Zum einen gibt es den klassischen ObjectContext und den DbContext und für beide Varianten gibt es die unterschiedlichsten Möglichkeiten sich die jeweiligen SQL Abfragen anzuzeigen.

Der ObjectContext

Hier gibt es keine native Möglichkeit sich den SQL Code anzuzeigen. Aber es gibt eine sehr einfache Lösung mit Hilfe einer Extension Methode. Die habe ich im MSDN Forum gefunden:

http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2a50ffd2-ed73-411d-82bc-c9c564623cb4/

Im Post findet man die Folgenden beiden Funktionen, mit denen man problemlos die jeweiligen SQL Befehle auslesen kann. Wer Probleme hat diese zum Laufen zu bekommen, evtl. mal in den Kommentaren im MSDN Forum weiterlesen, diese haben mir auch geholfen.

 public static string ToTraceString(this IQueryable query)
        {
            System.Reflection.MethodInfo toTraceStringMethod = query.GetType().GetMethod("ToTraceString");

            if (toTraceStringMethod != null)
                return toTraceStringMethod.Invoke(query, null).ToString();
            else
                return "";
        }
        
        public static string ToTraceString(this ObjectContext ctx)
        {
            Assembly entityAssemly = Assembly.Load(entityAssemblyName);

            Type updateTranslatorType = entityAssemly.GetType(
                "System.Data.Mapping.Update.Internal.UpdateTranslator");

            Type functionUpdateCommandType = entityAssemly.GetType(
                "System.Data.Mapping.Update.Internal.FunctionUpdateCommand");

            Type dynamicUpdateCommandType = entityAssemly.GetType(
                "System.Data.Mapping.Update.Internal.DynamicUpdateCommand");

            object[] ctorParams = new object[]
                        {
                            ctx.ObjectStateManager,
                            ((EntityConnection)ctx.Connection).GetMetadataWorkspace(),
                            (EntityConnection)ctx.Connection,
                            ctx.CommandTimeout
                        };

            object updateTranslator = Activator.CreateInstance(updateTranslatorType,
                BindingFlags.NonPublic | BindingFlags.Instance, null, ctorParams, null);

            MethodInfo produceCommandsMethod = updateTranslatorType
                .GetMethod("ProduceCommands", BindingFlags.Instance | BindingFlags.NonPublic);
            object updateCommands = produceCommandsMethod.Invoke(updateTranslator, null);

            List<DbCommand> dbCommands = new List<DbCommand>();

            foreach (object o in (IEnumerable)updateCommands)
            {
                if (functionUpdateCommandType.IsInstanceOfType(o))
                {
                    FieldInfo m_dbCommandField = functionUpdateCommandType.GetField(
                        "m_dbCommand", BindingFlags.Instance | BindingFlags.NonPublic);

                    dbCommands.Add((DbCommand)m_dbCommandField.GetValue(o));
                }
                else if (dynamicUpdateCommandType.IsInstanceOfType(o))
                {
                    MethodInfo createCommandMethod = dynamicUpdateCommandType.GetMethod(
                        "CreateCommand", BindingFlags.Instance | BindingFlags.NonPublic);

                    object[] methodParams = new object[]
                    {
                        updateTranslator,
                        new Dictionary<int, object>()
                    };

                    dbCommands.Add((DbCommand)createCommandMethod.Invoke(o, methodParams));
                }
                else
                {
                    throw new NotSupportedException("Unknown UpdateCommand Kind");
                }
            }


            StringBuilder traceString = new StringBuilder();
            foreach (DbCommand command in dbCommands)
            {
                traceString.AppendLine("=============== BEGIN COMMAND ===============");
                traceString.AppendLine();

                traceString.AppendLine(command.CommandText);
                foreach (DbParameter param in command.Parameters)
                {
                    traceString.AppendFormat("{0} = {1}", param.ParameterName, param.Value);
                    traceString.AppendLine();
                }

                traceString.AppendLine();
                traceString.AppendLine("=============== END COMMAND ===============");
            }

            return traceString.ToString();
        }

Hier ist es nun möglich die SQL Abfragen für Selects zu sehen und auch die Abfragen für Update, Insert und Delete. Das ganze kann dann z.B. folgendermaßen eingesetzt werden:

        public static void ObjectContextTrace()
        {
            //Neues Datenmodell erstellen, Achtung es muss nur ConnectionString in der App.Config "ModelContainer" angepasst werden.
            //die DB wird dann von "allein" angelegt.
            ModelContainer model = new ModelContainer();

            //Das Anlegen eines Objektes auslesen als SQL Statement
            Person person = new Person() { Name = "Müller", Vorname = "Max" };
            model.PersonMenge.AddObject(person);
            Console.Write(model.ToTraceString());
            model.SaveChanges();
            Console.ReadLine();

            //Eine Abfrage auslesen als SQL Statement.
            var namen = from ePerson in model.PersonMenge where ePerson.Name == "Müller" select ePerson;
            Console.Write(namen.ToTraceString());
            Console.ReadLine();
        }

Der DbContext

Um sich die SQL Abfragen für einen DBContext anzusehen, bietet .NET für Select Abfragen bereits eine mitgelieferte Möglichkeit, hier kann einfach “ToString()” auf das passende Query angewendet werden:

//Abfrage erstellen
var houses = from eHouse in modelDbContext.HausMenge where eHouse.Nummer == "31a" select eHouse;
Console.Write(houses.ToString());

Möchte man hier auch Update, Insert und Delete SQL Statements angezeigt bekommen, muss man einen Tracing und Caching Provider fürs das EF Installieren. Dieser steht auf CodePlex zum Download mittels NuGet bereit und muss unserem Projekt hinzugefügt werden. Auf der Homeseite von CodePlex ist in einfachen vier Schritten erläutert was genau gemacht werden muss, damit man die SQL Ausgaben bekommt.

Bei mir sieht das ganze dann z.B: folgendermaßen aus:

 public static void DbContextTrace()
 {
      //Einstellen wo das Log ausgegeben werden soll
      EFTracingProviderConfiguration.LogToConsole = true;

      //http://code.msdn.microsoft.com/EFProviderWrappers
      //Neues Datenmodell erstellen, Achtung es muss nur ConnectionString in der App.Config "ModelContainer" angepasst werden.
      ModelDbContextContainer modelDbContext = new ModelDbContextContainer("ModelDbContextContainer");
      //Beim Ersten ausführen auskommentieren und evtl. mit CreateDB ersetzten, macht probleme mit dem Wrapper
      //modelDbContext.Database.CreateIfNotExists();

      //Neues Objekt erstellen und der DB hinzufügen
      Haus haus = new Haus() { Nummer = "31a", Strasse = "Altenberger Straße" };
      modelDbContext.HausMenge.Add(haus);
       //Wird auf der Konsole ausgegeben, wenn Save Changes aufgerufen wird.
       modelDbContext.SaveChanges();
}

Wenn man jetzt die Ausgabe im Visual Studio beachtet, dann wird dort ausgegeben welche SQL Statement abgesetzt wurden und wie lange die jeweilige Ausführung gedauert hat. Auch Select Anweisungen sind hier zu finden, aber erst wenn diese auch wirklich ausgeführt wurden.

image

Mein Beispielprojekt auf CodePlex

Ich habe auch für dieses Beispiel ein Projekt auf CodePlex angelegt, welches man folgendermaßen finden kann:

https://squadwuschel.codeplex.com/

Dann unter “Source Code” –> “Browse” –> “Testprojekte” –> “EFTraceTest”

Hier könnt Ihr den kompletten Quelltext finden. Wenn jemand noch andere bzw. einfachere Möglichkeiten weiß wie man an die SQL Statements von EF Abfragen kommt, dann nicht zögern einen Kommentar abzugeben.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s