Mas*_*oud 77 c# sql logging entity-framework dbcontext
根据这个帖子,我们可以记录生成的SQLvia EF,但是怎么样DbContext.SaveChanges()?没有任何额外的框架,有没有简单的方法来完成这项工作?
Lor*_*ler 124
在实体框架6.0中,Database类具有属性Action<string> Log.因此,设置日志记录非常简单:
context.Database.Log = Console.WriteLine;
Run Code Online (Sandbox Code Playgroud)
对于更高级的需求,您可以设置拦截器.有关实体框架wiki的更多信息
Tom*_*gan 15
请参阅http://www.codeproject.com/Articles/499902/Profiling-Entity-Framework-5-in-code.我使用Code First,POCO DbContext,Entity Framework 5在asp.net mvc应用程序中实现了Cook先生的想法.
应用程序的上下文类派生自DbContext:
public class MyDbContext : DbContext
Run Code Online (Sandbox Code Playgroud)
上下文的构造函数挂钩了SavingChanges事件(我只想对调试版本进行昂贵的反射):
public MyDbContext(): base("MyDbContext")
{
#if DEBUG
((IObjectContextAdapter)this).ObjectContext.SavingChanges += new EventHandler(objContext_SavingChanges);
#endif
}
Run Code Online (Sandbox Code Playgroud)
保存更改事件将生成的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<object>)produceCommands.Invoke(translator, null);
foreach (var cmd in commands)
{
var identifierValues = new Dictionary<int, object>();
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());
}
Run Code Online (Sandbox Code Playgroud)
TPA*_*OPA 10
对于短期日志记录,我只是放入DbContext构造函数:
Database.Log = x => Debug.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)
添加/删除SQL的日志记录非常快.对于长期使用期限,可以用支票包裹
#IFDEF DEBUG // or something similar
Run Code Online (Sandbox Code Playgroud)
如果要捕获使用拦截器使用EF6生成的实际SQL(可能稍后播放),您可以执行以下操作.
创建你的拦截器
public class InsertUpdateInterceptor : IDbCommandInterceptor
{
public virtual void NonQueryExecuting(
DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
logCommand(command);
}
public virtual void ReaderExecuting(
DbCommand command, DbCommandInterceptionContext<DbDataReader> 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<object> 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<int> interceptionContext)
{
}
public void ReaderExecuted(
DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
public void ScalarExecuted(
DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
}
}
Run Code Online (Sandbox Code Playgroud)
而且你还需要注册你的拦截器.如果您在ASP.NET应用程序中执行此操作,请确保只执行一次,否则您将最终多次拦截相同的请求.
示例DAO
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
62445 次 |
| 最近记录: |