我正在尝试在我的网络应用程序中记录所有数据库操作。
我有一个在数据库上写的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次......
- 在8毫秒内完成,结果为:SqlDataReader
不可能同时拥有完整的INSERT语句吗?
答案 0 :(得分:3)
您必须使用比context.Database.Log
更复杂的机制:
https://msdn.microsoft.com/en-us/library/dn469464(v=vs.113).aspx
除了提到context.Database.Log
之外,还有DatabaseLogFormatter
和IDbCommandInterceptor
。
以下是链接中的示例:
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()
的结果,并且您将看到对象和对象数据的状态。