在Entity Framework中记录插入和更新命令sql查询

时间:2017-08-25 12:07:08

标签: c# entity-framework entity-framework-6

我正在尝试在我的网络应用程序中记录所有数据库操作。

我有一个在数据库上写的LOGS类

public partial class LOGS
{
    public static int AddLogs(LOGS log)
    {
        int ret = 0;
        try
        {
            using (var context = new Entities())
            {
                log.Data = DateTime.Now;
                context.LOGS.Add(log);
                ret += context.SaveChanges();
            }
            return ret;
        }
        catch (Exception ex)
        {
            string w = ex.Message;
            return -1;
        }
    }

    public static void WriteDetailed(string query)
    {
        if (u == null || u.LOGLevel == 0)
            return;
        else
        {
            StackTrace st = new StackTrace();
            StackFrame sf = st.GetFrame(1);
            if (sf != null)
            {
                MethodBase currentMethodName = sf.GetMethod();
                String metodo = currentMethodName.ReflectedType.FullName + " " + currentMethodName.Name;

                LOGS newLog = new LOGS();
                newLog.Tipo = "Q";
                newLog.TipoLog = metodo;
                newLog.Testo = query;

                AddLogs(newLog);
            }
        }
    }
}

以这种方式记录方法的选择操作:

 public static List<Agent> GetAgents()
    {
        try
        {
            using (var context = new Entities())
            {
                var entities = (from a in context.Agent
                                select a);
                LOGS.WriteDetailed(entities.ToString());
                return entities.ToList();
            }
        }
        catch (Exception ex)
        {
            LOGS.WriteExceptionLog(ex);
            return null;
        }
    }

但对我来说,无法记录插入,更新结束删除语句

我读到我可以使用这种方法

context.Database.Log = msg => LOGS.WriteDetailed(msg);

我试图以这种方式使用它:

 public static bool AddAgent(Agent newAgent)
    {
        bool ret = true;

        using (var context = new Entities())
        {
            using (var dbContextTransaction = context.Database.BeginTransaction())
            {
                try
                {
                    newAgent.DateLM = DateTime.Now;
                    context.Agent.Add(newAgent);

                    context.Database.Log = msg => LOGS.WriteDetailed(msg);
                    ret = ret && context.SaveChanges() > 0;
                    if (ret)
                        dbContextTransaction.Commit();
                    else
                        dbContextTransaction.Rollback();

                    return ret;

                }
                catch (Exception ex)
                {
                    LOGS.WriteExceptionLog(ex);
                    return false;
                }
            }
        }

    }

这可行,但是以一种奇怪的方式:在单个INSERT操作中,它将传递WriteDetailed方法8次......

  1. INSERT [dbo]。[Agent]([Name],[Active],[UserLM],[DateLM])VALUES(@ 0,@ 1,@ 2,@ 3)SELECT [ID_Agent] FROM [dbo] 。[代理] WHERE @@ ROWCOUNT&gt; 0 AND [ID_Agent] = scope_identity()
  2. (空) 3 .-- @ 0:'a'(Type = AnsiString,Size = 100)
  3. - @ 1:'True'(Type = Boolean)
  4. - @ 2:'1'(Type = Int32)
  5. - @ 3:'25 / 08/2017 2017 13:34:16'(Type = DateTime2)
  6. - 执行时间为25/08/2017 13:46:17 +02:00
  7. - 在8毫秒内完成,结果为:SqlDataReader

    不可能同时拥有完整的INSERT语句吗?

3 个答案:

答案 0 :(得分:3)

您必须使用比context.Database.Log更复杂的机制: https://msdn.microsoft.com/en-us/library/dn469464(v=vs.113).aspx

除了提到context.Database.Log之外,还有DatabaseLogFormatterIDbCommandInterceptor。 以下是链接中的示例:

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); 
        } 
    } 
}

最简单的设置方法是使用静态方法:

DbInterception.Add(new NLogCommandInterceptor());

答案 1 :(得分:2)

您需要累积行并检测SQL语句结束。例如。当行以--开头时,它显然超过了SQL语句的结尾。如果您想捕获注释(和参数),可以捕获-- Completed行。因此,直接调用WriteDetailed,您可以调用方法来聚合和分析EF生成的SQL文本,并根据需要自己调用WriteDetailed

LOGS课程中,添加以下内容:

private static StringBuilder sb = new StringBuilder();

public static void SqlLineGenerated(string line)
{
    sb.Append(line);

    if (line.StartsWith("-- Completed", StringComparison.OrdinalIgnoreCase))
    {
        WriteDetailed(sb.ToString());
        sb = new StringBuilder();
    }
}

接下来,设置日志记录如下:

context.Database.Log = msg => LOGS.SqlLineGenerated(msg);

你很高兴。

答案 2 :(得分:0)

您可以聚合所有行,直到获得Executing行,但它不会在没有参数的情况下对一个平面SQL进行遗传。

或者,您可以尝试在ChangeTracker调用之前使用SaveChanges收集数据。您可以遍历context.ChangeTracker.Entries()的结果,并且您将看到对象和对象数据的状态。