Як я магу ўвайсці згенераваны SQL з DbContext.SaveChanges () у маёй праграме?

Згодна гэта нітка, мы можам увайсці згенераваны SQL праз EF , але што DbContext.SaveChanges() ? Ці ёсць просты спосаб зрабіць гэтую працу без якіх-небудзь дадатковых рамак?

64
не, я хачу ўвайсці згенераваны SQL заявы EF
дададзена аўтар Masoud, крыніца
не, я хачу ўвайсці згенераваны SQL заявы EF
дададзена аўтар Masoud, крыніца
не, я хачу ўвайсці згенераваны SQL заявы EF
дададзена аўтар Masoud, крыніца
вы хочаце зрабіць нешта накшталт гэтага? stackoverflow.com/questions/11922552/…
дададзена аўтар Kirsten Greed, крыніца
Праверыць гэтую спасылку: jkowalski.com/2010/04/23/& hellip;
дададзена аўтар Alaa Masoud, крыніца
Праверыць гэтую спасылку: jkowalski.com/2010/04/23/& hellip;
дададзена аўтар Alaa Masoud, крыніца
Праверыць гэтую спасылку: jkowalski.com/2010/04/23/& hellip;
дададзена аўтар Alaa Masoud, крыніца

12 адказы

In entity framework 6.0, the Database class has a property Action Log. so setting up logging is as easy as:

context.Database.Log = Console.WriteLine;

For more advanced needs you can set up an interceptor. More info on the entity framework wiki

109
дададзена
См: Entity Framework Logging і Перахапіўшы базы дадзеных аперацый (Ef6 Onwards) тут: msdn.microsoft.com/en-us/library/dn469464 (v = vs.113) .aspx
дададзена аўтар DeveloperDan, крыніца
Public Sub New() Database.Log = Sub (s) Debug.WriteLine (s) End Sub End Sub
дададзена аўтар Bernhard Döbler, крыніца
Гэты выхад часопіса атрымлівае перамяшаны пры абслугоўванні некалькіх адначасовых вэб-запытаў. Такім чынам, я стварыў новы Q і знайшоў A - гл stackoverflow.com/questions/46984518/…
дададзена аўтар Todd, крыніца
або пакласці яго ў DbContext CTOR 'Database.Log = s => Debug.WriteLine (с);'
дададзена аўтар Soren, крыніца
Праверыў усе адказы і не бачылі; як мы робім гэта ў EF Ядры?
дададзена аўтар Scott K. Fraley, крыніца

См http://www.codeproject.com/Articles/499902/Profiling-Entity -framework-5-у-кода . Я рэалізаваў ідэю г-Кука ў ASP.NET MVC прыкладання з дапамогай Code First, POCO DbContext, Entity Framework 5.

Клас кантэксту для прымянення выцякае з DbContext:

public class MyDbContext : DbContext

Канструктар для кантэксту падлучае падзея SavingChanges (я толькі хачу, каб зрабіць дарагое адлюстраванне для адладкавыя зборак):

public MyDbContext(): base("MyDbContext")
{
#if DEBUG
    ((IObjectContextAdapter)this).ObjectContext.SavingChanges += new EventHandler(objContext_SavingChanges);
#endif
}

Падзея змены эканоміі піша згенераваны SQL ў акне высновы. Код, які я скапіяваў з г Кука пераўтворыць DbParameter да SqlParamter, які я пакідаю як ёсць, таму што я удараючы SQL Server, але я мяркую, што пераўтварэнне пацерпіць няўдачу, калі вы ўдараюць якой-небудзь іншай выгляд базы дадзеных.

public void objContext_SavingChanges(object sender, EventArgs e)
    {
        var commandText = new StringBuilder();

        var conn = sender.GetType()
             .GetProperties(BindingFlags.Public | BindingFlags.Instance)
             .Where(p => p.Name == "Connection")
             .Select(p => p.GetValue(sender, null))
             .SingleOrDefault();
        var entityConn = (EntityConnection)conn;

        var objStateManager = (ObjectStateManager)sender.GetType()
              .GetProperty("ObjectStateManager", BindingFlags.Instance | BindingFlags.Public)
              .GetValue(sender, null);

        var workspace = entityConn.GetMetadataWorkspace();

        var translatorT =
            sender.GetType().Assembly.GetType("System.Data.Mapping.Update.Internal.UpdateTranslator");

        var translator = Activator.CreateInstance(translatorT, BindingFlags.Instance |
            BindingFlags.NonPublic, null, new object[] {objStateManager,workspace,
            entityConn,entityConn.ConnectionTimeout }, CultureInfo.InvariantCulture);

        var produceCommands = translator.GetType().GetMethod(
            "ProduceCommands", BindingFlags.NonPublic | BindingFlags.Instance);

        var commands = (IEnumerable)produceCommands.Invoke(translator, null);

        foreach (var cmd in commands)
        {
            var identifierValues = new Dictionary(); var dcmd = (DbCommand)cmd.GetType() .GetMethod("CreateCommand", BindingFlags.Instance | BindingFlags.NonPublic) .Invoke(cmd, new[] { translator, identifierValues }); foreach (DbParameter param in dcmd.Parameters) { var sqlParam = (SqlParameter)param; commandText.AppendLine(String.Format("declare {0} {1} {2}", sqlParam.ParameterName, sqlParam.SqlDbType.ToString().ToLower(), sqlParam.Size > 0 ? "(" + sqlParam.Size + ")" : "")); commandText.AppendLine(String.Format("set {0} = '{1}'", sqlParam.ParameterName, sqlParam.SqlValue)); } commandText.AppendLine(); commandText.AppendLine(dcmd.CommandText); commandText.AppendLine("go"); commandText.AppendLine(); } System.Diagnostics.Debug.Write(commandText.ToString()); } 
13
дададзена
Я не згодны з выкарыстаннем слова «памылка» @LachlanB, але да вы правільна, гэта не стварае ідэальны SQL, SQL, павінен быць зменены. Ці вы маглі б дадаць трохі больш логікі і атрымаць ідэальны SQL.
дададзена аўтар Tom Regan, крыніца
Ён не спрабуе генераваць правільны SQL, ён спрабуе паказаць праграмны інжынер SQL, генераваны Entity Framework 5, так што сказаў інжынер можа адладжваць праблемы. Звярніце ўвагу на дырэктыву препроцессора #debug, і што тэкст запісваецца ў акно вываду IDE. Тэкст павінен быць неабходна ўручную скапіяваць і ўставіць у SSMS ці нешта падобнае, а ў некаторых выпадках распрацоўніку трэба будзе рэдагаваць кв перад выкананнем. Гэта не памылка, гэта проста тое, што код прызначаны.
дададзена аўтар Tom Regan, крыніца
Існуе памылка ў гэтым кодзе sqlParam.SqlValue не паўцякалі, так што любое значэнне з адзіночнай двукоссі будуць несапраўдныя SQL .. і будзе таксама пакінуць вас адкрыты для ін'екцыі SQL.
дададзена аўтар Rocklan, крыніца
Як гэта не памылка? Гэта недапушчальныя SQL ў пэўных умовах, і ён спрабуе згенераваць правільны SQL, так што гэта памылка любога вызначэння словы.
дададзена аўтар Rocklan, крыніца
Добра, не магу з гэтым паспрачацца, я выкарыстоўваю яго для розных мэтаў. Дарэчы ёсць яшчэ адна праблема (не памылка), sqlParam.Size -1 для NVARCHAR (макс) тыпу дадзеных, а згенераваны SQL будзе пакараціць тэкст аж да аднаго знака.
дададзена аўтар Rocklan, крыніца

Калі вы хочаце, каб захапіць фактычны SQL, які быў створаны з дапамогай Ef6 (магчыма прайграць пазней) з дапамогай перахопніка, вы можаце зрабіць наступнае.

<�Моцны> Стварыць перахопнік

public class InsertUpdateInterceptor : IDbCommandInterceptor
{
    public virtual void NonQueryExecuting(
        DbCommand command, DbCommandInterceptionContext interceptionContext)
    {
        logCommand(command);
    }

    public virtual void ReaderExecuting(
        DbCommand command, DbCommandInterceptionContext interceptionContext)
    {
       //this will capture all SELECT queries if you care about them..
       //however it also captures INSERT statements as well 
        logCommand(command);
    }

    public virtual void ScalarExecuting(
     DbCommand command, DbCommandInterceptionContext interceptionContext)
    {
        logCommand(command);
    }


    private void logCommand(DbCommand dbCommand)
    {
        StringBuilder commandText = new StringBuilder();

        commandText.AppendLine("-- New statement generated: " + System.DateTime.Now.ToString());
        commandText.AppendLine();

       //as the command has a bunch of parameters, we need to declare
       //those parameters here so the SQL will execute properly

        foreach (DbParameter param in dbCommand.Parameters)
        {
            var sqlParam = (SqlParameter)param;

            commandText.AppendLine(String.Format("DECLARE {0} {1} {2}",
                                                    sqlParam.ParameterName,
                                                    sqlParam.SqlDbType.ToString().ToLower(),
                                                    getSqlDataTypeSize(sqlParam));

            var escapedValue = sqlParam.SqlValue.replace("'", "''");
            commandText.AppendLine(String.Format("SET {0} = '{1}'", sqlParam.ParameterName, escapedValue ));
            commandText.AppendLine();
        }

        commandText.AppendLine(dbCommand.CommandText);
        commandText.AppendLine("GO");
        commandText.AppendLine();
        commandText.AppendLine();

        System.IO.File.AppendAllText("outputfile.sql", commandText.ToString());
    }

    private string getSqlDataTypeSize(SqlParameter param)
    {
        if (param.Size == 0)
        {
            return "";
        }

        if (param.Size == -1)
        {
            return "(MAX)";
        }

        return "(" + param.Size + ")";
    }


   //To implement the IDbCommandInterceptor interface you need to also implement these methods like so

    public void NonQueryExecuted(
        DbCommand command, DbCommandInterceptionContext interceptionContext) { } public void ReaderExecuted( DbCommand command, DbCommandInterceptionContext interceptionContext) { } public void ScalarExecuted( DbCommand command, DbCommandInterceptionContext interceptionContext) { } } 

І вы таксама павінны зарэгістраваць свой перахопнік. Калі вы робіце гэта ў дадатку ASP.NET пераканайцеся, што вы робіце гэта толькі адзін раз, у адваротным выпадку вы будзеце ў канчатковым выніку перахопліваць той жа запыт некалькі разоў.

<�Моцны> Прыклад ДАО </моцны>

public class MyDataDAO
{
    private static bool isDbInterceptionInitialised = false;

    public MyDataDAO()
    {
        if (!isDbInterceptionInitialised)
        {
            DbInterception.Add(new InsertUpdateInterceptor());
            isDbInterceptionInitialised = true;
        }
    }

    public void Insert(string dataToInsert)
    {
        using (myentities context = new myentities())
        {
            MyData myData = new MyData();
            myData.data = dataToInsert;

           //this will trigger the interceptor
            context.SaveChanges();
        }
    }
}
7
дададзена
<�Код> NLogCommandInterceptor для EF6 blog.oneunicorn.com/2013/05/14/… , любы SerilogCommandInterceptor выкарыстоўваючы Serilog ?
дададзена аўтар Kiquenet, крыніца
Я лічу, што ваш прыклад выдатна, дзякуй! Аднак гэта, падобна, не працуе, таму што ўласцівасць SqlValue з SqlParameter аб'екта з'яўляецца тып аб'екта, так што doen't ведаць метад «замяніць». <�Код> sqlParam.SqlValue.replace ( " '", "'");
дададзена аўтар Mister Q, крыніца

Для кароткачасовых лесанарыхтовак, я проста пакласці ў DbContext канструктар:

Database.Log = x => Debug.WriteLine(x);

Даволі хутка, каб дадаць/выдаліць рэгістрацыю SQL. Для тэрміну доўгатэрміновага выкарыстання, можа быць абгорнутыя ў выглядзе чэкаў з

#IFDEF DEBUG//or something similar
6
дададзена

Гэта робіць тое ж самае, але кожны раз, калі вы выкарыстоўваеце свой кантэкст, ён будзе пісаць SQL-запыт у акне высновы. Розніца заключаецца ў тым, што ён не кампілюецца ў рэлізе.

public MyEntitities()
    : base()
{
    Database.Log = s => System.Diagnostics.Trace.WriteLine(s);
}

Гэта StackOverflow тлумачыць розніцу паміж трасіроўкі і адладкі.

2
дададзена

Гэта робіць тое ж самае, але кожны раз, калі вы выкарыстоўваеце свой кантэкст, ён будзе пісаць SQL-запыт у акне высновы. Розніца заключаецца ў тым, што ён не кампілюецца ў рэлізе.

public MyEntitities()
    : base()
{
    Database.Log = s => System.Diagnostics.Trace.WriteLine(s);
}

Гэта StackOverflow тлумачыць розніцу паміж трасіроўкі і адладкі.

2
дададзена

Код Том Рыган абноўлены EF6.

    public void objContext_SavingChanges(object sender, EventArgs e)
    {
        var commandText = new StringBuilder();

        var conn = sender.GetType()
             .GetProperties(BindingFlags.Public | BindingFlags.Instance)
             .Where(p => p.Name == "Connection")
             .Select(p => p.GetValue(sender, null))
             .SingleOrDefault();
        var entityConn = (EntityConnection)conn;

        var objStateManager = (System.Data.Entity.Core.Objects.ObjectStateManager)sender.GetType()
              .GetProperty("ObjectStateManager", BindingFlags.Instance | BindingFlags.Public)
              .GetValue(sender, null);

        var workspace = entityConn.GetMetadataWorkspace();

        var translatorT =
            sender.GetType().Assembly.GetType("System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator");

        var entityAdapterT =
            sender.GetType().Assembly.GetType("System.Data.Entity.Core.EntityClient.Internal.EntityAdapter");
        var entityAdapter = Activator.CreateInstance(entityAdapterT, BindingFlags.Instance |
            BindingFlags.NonPublic | BindingFlags.Public, null, new object[] { sender }, System.Globalization.CultureInfo.InvariantCulture);

        entityAdapterT.GetProperty("Connection").SetValue(entityAdapter, entityConn);

        var translator = Activator.CreateInstance(translatorT, BindingFlags.Instance |
            BindingFlags.NonPublic | BindingFlags.Public, null, new object[] { entityAdapter }, System.Globalization.CultureInfo.InvariantCulture);

        var produceCommands = translator.GetType().GetMethod(
            "ProduceCommands", BindingFlags.NonPublic | BindingFlags.Instance);

        var commands = (IEnumerable)produceCommands.Invoke(translator, null);

        foreach (var cmd in commands)
        {
            var identifierValues = new Dictionary(); var dcmd = (System.Data.Common.DbCommand)cmd.GetType() .GetMethod("CreateCommand", BindingFlags.Instance | BindingFlags.NonPublic) .Invoke(cmd, new[] { identifierValues }); foreach (System.Data.Common.DbParameter param in dcmd.Parameters) { var sqlParam = (SqlParameter)param; commandText.AppendLine(String.Format("declare {0} {1} {2}", sqlParam.ParameterName, sqlParam.SqlDbType.ToString().ToLower(), sqlParam.Size > 0 ? "(" + sqlParam.Size + ")" : "")); commandText.AppendLine(String.Format("set {0} = '{1}'", sqlParam.ParameterName, sqlParam.SqlValue)); } commandText.AppendLine(); commandText.AppendLine(dcmd.CommandText); commandText.AppendLine("go"); commandText.AppendLine(); } System.Diagnostics.Debug.Write(commandText.ToString()); } 
2
дададзена

Гэта павінна дапамагчы, то EFTracingProvider

http://code.msdn.microsoft.com/EFProviderWrappers

1
дададзена
Ці ёсць рашэнне для працы з DbContext таксама?
дададзена аўтар Masoud, крыніца
дададзена аўтар Wiktor Zychla, крыніца

Гэта павінна дапамагчы, то EFTracingProvider

http://code.msdn.microsoft.com/EFProviderWrappers

1
дададзена
Ці ёсць рашэнне для працы з DbContext таксама?
дададзена аўтар Masoud, крыніца
дададзена аўтар Wiktor Zychla, крыніца

Вы можаце выкарыстоўваць SQL Server Profiler і запусціць яго на сервер базы дадзеных вы падлучаецеся.

1
дададзена
Нягледзячы на ​​тое, што гэта спосаб увайсці SQL, гэта апошні сродак. Гэта патрабуе спецыяльных дазволаў на сэрвэры, ня інтэгруецца з пратакалявання прыкладанняў, часопісаў больш, чым тое, што вы шукаеце, і не мае магчымасці асацыяваць вашыя заявы EF згенераванай SQL.
дададзена аўтар Gabe, крыніца

Вы можаце выкарыстоўваць SQL Server Profiler і запусціць яго на сервер базы дадзеных вы падлучаецеся.

1
дададзена
Нягледзячы на ​​тое, што гэта спосаб увайсці SQL, гэта апошні сродак. Гэта патрабуе спецыяльных дазволаў на сэрвэры, ня інтэгруецца з пратакалявання прыкладанняў, часопісаў больш, чым тое, што вы шукаеце, і не мае магчымасці асацыяваць вашыя заявы EF згенераванай SQL.
дададзена аўтар Gabe, крыніца

Вы можаце выкарыстоўваць SQL Server Profiler і запусціць яго на сервер базы дадзеных вы падлучаецеся.

1
дададзена
Нягледзячы на ​​тое, што гэта спосаб увайсці SQL, гэта апошні сродак. Гэта патрабуе спецыяльных дазволаў на сэрвэры, ня інтэгруецца з пратакалявання прыкладанняў, часопісаў больш, чым тое, што вы шукаеце, і не мае магчымасці асацыяваць вашыя заявы EF згенераванай SQL.
дададзена аўтар Gabe, крыніца