前言
ef 开发效率确实很高也很便捷,但当它发生错误时,也挺让人头疼的,为什么?因为 ef 就像是一个黑盒子,一切全被封装起来,出错的时候很难定位原因,如果能够知道并打印 ef 生成的 sql 语句,对于定位 ef 错误,就很有帮助。
程序员的才智是无限的,虽然 ef 有这个那个的问题,但程序员却总比这些问题多一个办法。
下面分享一个 .net 通过监听器拦截 ef 消息写日志的详细例子。
step by step 步骤
-
创建自定义监听器类,拦截 ef 的命令执行事件(留意注释)
/// <summary> /// 监听并写 ef 生成的 sql 到日志 /// </summary> public class efintercepterlogging : idbcommandinterceptor { /// <summary> /// 实现接口的 nonqueryexecuting 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void nonqueryexecuting( dbcommand command, dbcommandinterceptioncontext<int> interceptioncontext) { logwhenexecuting(command, interceptioncontext); } /// <summary> /// 实现接口的 nonqueryexecuted 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void nonqueryexecuted( dbcommand command, dbcommandinterceptioncontext<int> interceptioncontext) { logiferror(command, interceptioncontext); } /// <summary> /// 实现接口的 readerexecuting 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void readerexecuting( dbcommand command, dbcommandinterceptioncontext<dbdatareader> interceptioncontext) { logwhenexecuting(command, interceptioncontext); } /// <summary> /// 实现接口的 readerexecuted 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void readerexecuted( dbcommand command, dbcommandinterceptioncontext<dbdatareader> interceptioncontext) { logiferror(command, interceptioncontext); } /// <summary> /// 实现接口的 scalarexecuting 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void scalarexecuting( dbcommand command, dbcommandinterceptioncontext<object> interceptioncontext) { logwhenexecuting(command, interceptioncontext); } /// <summary> /// 实现接口的 scalarexecuted 方法 /// </summary> /// <param name="command"></param> /// <param name="interceptioncontext"></param> public void scalarexecuted( dbcommand command, dbcommandinterceptioncontext<object> interceptioncontext) { logiferror(command, interceptioncontext); } /// <summary> /// 写 ef 执行中的 sql 日志,debug 级别,用在 executing 方法 /// </summary> /// <typeparam name="tresult"></typeparam> /// <param name="command"></param> /// <param name="interceptioncontext"></param> private void logwhenexecuting<tresult>( dbcommand command, dbcommandinterceptioncontext<tresult> interceptioncontext) { logger.debugformat("executing the following sql: [{0}]", command.commandtext); } /// <summary> /// 出现异常时写日志到 log4net /// </summary> /// <typeparam name="tresult"></typeparam> /// <param name="command"></param> /// <param name="interceptioncontext"></param> private void logiferror<tresult>( dbcommand command, dbcommandinterceptioncontext<tresult> interceptioncontext) { if (interceptioncontext.exception != null) { var errmsg = new stringbuilder(16); errmsg.appendline("error occurred when executing the following sql: "); errmsg.appendline(command.commandtext); foreach (dbparameter param in command.parameters) { errmsg.appendline($"parametername:[{param.parametername}] -- dbtype:[{param.dbtype}] -- value:[{param.value}]"); } logger.error(errmsg, interceptioncontext.exception); } } }
-
在 global.asax 中的 application_start 方法注册监听器
protected void application_start() { arearegistration.registerallareas(); filterconfig.registerglobalfilters(globalfilters.filters); routeconfig.registerroutes(routetable.routes); bundleconfig.registerbundles(bundletable.bundles); //autofac注册 autofacconfig.registerconfig(); //注册 ef log 监听器 dbinterception.add(new efintercepterlogging()); }
-
这样就实现了监听器拦截 ef 消息写日志的功能,当运行程序执行 ef 语句时,就会自动将 ef 生成的 sql 写到日志文件中
总结
通过实现自定义监听器类并注册监听器,可以跟踪和记录 ef 的操作和事件,在开发过程中更好地了解和调试 ef 的行为,不失为排查 ef 问题和优化 ef 性能的一个好方法。
发表评论