一、關於EF6的記錄Sql語句,一個老生長談的問題。 他生成的sql語句實在是爛,你們都這樣說sql
二、EF6 更新刪除不方便,沒有批量操做。因此,有人出了EF6.Extend 你們用起來也很爽緩存
基於以上兩點,我也嘗試着使用 EF6.Extend 。本覺得能夠很好的,很美好。沒有想到我遇到了一個大問題。async
我須要 經過程序記錄 EF執行的Sql語句,固然也包括 EF6.Extend 執行的Sql語句。(不是經過SqlProfiler)ide
在網上查找,發現 了一篇文章,我就這樣抄下來了。(太匆忙解決問題,忘記了哪一篇)ui
繼承了 System.Data.Entity.Infrastructure.Interception.DbCommandInterceptor ,實現相關方法。 而後在Main方法(程序入口)進行添加 DbInterception.Add(new EFIntercepterLogging()); spa
1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity.Infrastructure.Interception; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace EF_Sqlite 10 { 11 class EFIntercepterLogging : DbCommandInterceptor 12 { 13 private readonly Stopwatch _stopwatch = new Stopwatch(); 14 public override void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 15 { 16 base.ScalarExecuting(command, interceptionContext); 17 _stopwatch.Restart(); 18 } 19 public override void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 20 { 21 _stopwatch.Stop(); 22 if (interceptionContext.Exception != null) 23 { 24 Trace.TraceError("Exception:{1} \r\n --> Error executing command: {0}", command.CommandText, interceptionContext.Exception.ToString()); 25 } 26 else 27 { 28 string txt=string.Format("\r\n執行時間:{0} 毫秒\r\n-->ScalarExecuted.Command:{1}\r\n", _stopwatch.ElapsedMilliseconds, command.CommandText); 29 Console.WriteLine(txt); 30 Trace.TraceInformation(txt); 31 } 32 base.ScalarExecuted(command, interceptionContext); 33 } 34 public override void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 35 { 36 base.NonQueryExecuting(command, interceptionContext); 37 _stopwatch.Restart(); 38 } 39 public override void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 40 { 41 42 _stopwatch.Stop(); 43 if (interceptionContext.Exception != null) 44 { 45 Trace.TraceError("Exception:{1} \r\n --> Error executing command:\r\n {0}", command.CommandText, interceptionContext.Exception.ToString()); 46 } 47 else 48 { 49 50 string txt = string.Format("\r\n執行時間:{0} 毫秒\r\n-->ScalarExecuted.Command:{1}\r\n", _stopwatch.ElapsedMilliseconds, command.CommandText); 51 Console.WriteLine(txt); 52 Trace.TraceInformation(txt); 53 } 54 base.NonQueryExecuted(command, interceptionContext); 55 } 56 public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext) 57 { 58 base.ReaderExecuting(command, interceptionContext); 59 _stopwatch.Restart(); 60 } 61 public override void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext) 62 { 63 _stopwatch.Stop(); 64 if (interceptionContext.Exception != null) 65 { 66 Trace.TraceError("Exception:{1} \r\n --> Error executing command:\r\n {0}", command.CommandText, interceptionContext.Exception.ToString()); 67 } 68 else 69 { 70 string txt = string.Format("\r\n執行時間:{0} 毫秒\r\n-->ScalarExecuted.Command:{1}\r\n", _stopwatch.ElapsedMilliseconds, command.CommandText); 71 Console.WriteLine(txt); 72 Trace.TraceInformation(txt); 73 } 74 base.ReaderExecuted(command, interceptionContext); 75 } 76 77 78 } 79 }
經過EF正常的操做是能夠記錄到SQL語句的,而經過EF.Extend執行的刪除操做是沒法獲取sql的。我想,是否是我寫錯了,可網上根本沒有關於EF.Extend 記錄生成SQL的隻言片語,可能你們都沒有遇到這樣的問題。 pwa
只能硬着頭皮,翻源碼。日誌
通過翻看EF.Extend的源碼,發現他是直接用Command執行的sql,再翻 EF的源碼發現,EF是繞了很大一圈來執行的SQL code
找到EF的這裏,我明白了orm
1 public virtual int NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext) 2 { 3 Check.NotNull(command, "command"); 4 Check.NotNull(interceptionContext, "interceptionContext"); 5 6 return _internalDispatcher.Dispatch( 7 command, 8 (t, c) => t.ExecuteNonQuery(), 9 new DbCommandInterceptionContext<int>(interceptionContext), 10 (i, t, c) => i.NonQueryExecuting(t, c), 11 (i, t, c) => i.NonQueryExecuted(t, c)); 12 }
而,EF.Extend的代碼是這樣寫的
1 private int InternalDelete<TEntity>(ObjectContext objectContext, EntityMap entityMap, ObjectQuery<TEntity> query) 2 where TEntity : class 3 #endif 4 { 5 DbConnection deleteConnection = null; 6 DbTransaction deleteTransaction = null; 7 DbCommand deleteCommand = null; 8 bool ownConnection = false; 9 bool ownTransaction = false; 10 11 try 12 { 13 // get store connection and transaction 14 var store = GetStore(objectContext); 15 deleteConnection = store.Item1; 16 deleteTransaction = store.Item2; 17 18 if (deleteConnection.State != ConnectionState.Open) 19 { 20 deleteConnection.Open(); 21 ownConnection = true; 22 } 23 24 if (deleteTransaction == null) 25 { 26 deleteTransaction = deleteConnection.BeginTransaction(); 27 ownTransaction = true; 28 } 29 30 31 deleteCommand = deleteConnection.CreateCommand(); 32 deleteCommand.Transaction = deleteTransaction; 33 if (objectContext.CommandTimeout.HasValue) 34 deleteCommand.CommandTimeout = objectContext.CommandTimeout.Value; 35 36 var innerSelect = GetSelectSql(query, entityMap, deleteCommand); 37 38 var sqlBuilder = new StringBuilder(innerSelect.Length * 2); 39 40 sqlBuilder.Append("DELETE "); 41 sqlBuilder.Append(entityMap.TableName); 42 sqlBuilder.AppendLine(); 43 44 sqlBuilder.AppendFormat("FROM {0} AS j0 INNER JOIN (", entityMap.TableName); 45 sqlBuilder.AppendLine(); 46 sqlBuilder.AppendLine(innerSelect); 47 sqlBuilder.Append(") AS j1 ON ("); 48 49 bool wroteKey = false; 50 foreach (var keyMap in entityMap.KeyMaps) 51 { 52 if (wroteKey) 53 sqlBuilder.Append(" AND "); 54 55 sqlBuilder.AppendFormat("j0.[{0}] = j1.[{0}]", keyMap.ColumnName); 56 wroteKey = true; 57 } 58 sqlBuilder.Append(")"); 59 60 deleteCommand.CommandText = sqlBuilder.ToString(); 61 62 #if NET45 63 int result = async 64 ? await deleteCommand.ExecuteNonQueryAsync().ConfigureAwait(false) 65 : deleteCommand.ExecuteNonQuery(); 66 #else 67 int result = deleteCommand.ExecuteNonQuery(); 68 #endif 69 // only commit if created transaction 70 if (ownTransaction) 71 deleteTransaction.Commit(); 72 73 return result; 74 } 75 finally 76 { 77 if (deleteCommand != null) 78 deleteCommand.Dispose(); 79 80 if (deleteTransaction != null && ownTransaction) 81 deleteTransaction.Dispose(); 82 83 if (deleteConnection != null && ownConnection) 84 deleteConnection.Close(); 85 } 86 }
通過分析,是這個道理,按照這個邏輯,EF.Extend沒有按照EF的邏輯寫,因此,他不能經過這種方式記錄Sql。
恍然大悟後,我這樣執行的Sql
System.Data.Common.DbConnection con = t.Database.Connection; System.Data.Common.DbCommand command = con.CreateCommand(); con.Open(); command.CommandText = "delete from area where 1=2 and 4=9"; DbInterception.Dispatch.Command.NonQuery(command, new DbCommandInterceptionContext());
就這樣,我 經過統一的方式,獲取到了我本身執行的Sql語句,和EF執行的Sql語句
原本是打算用EF.Extend的,看到這裏,我決定不用了,有點殺雞用牛刀。(其實,EF.Extend 不只擴展了修改和刪除的方法,還擴展了 EF沒有的二級緩存,等等。若是隻是用到修改刪除的擴展方法,那能夠放棄Extend了。)