前言
很長一段時間沒有寫博客了,今天補上一篇吧,偶爾發現不太願意寫博客了,太耗費時間,不過還是在堅持當中,畢竟或許寫出來的東西能幫到一些童鞋吧,接下來我們直奔主題。無論是在EF 6.x還是EF Core中對於原始查詢的APi都比較雞肋,比如我們只想查詢單個值,它們是不支持的,比如我們只想有些列,它們也是不支持的,太多太多不支持,唯一支持的是只能返回表中所有列即類中所有字段。所以大部分情況下我都是寫原生SQL,原始查詢都沒怎么用到過,最近有對熱愛EF的同行問到怎么利用SqlQuery實現動態查詢,我沒有答案,壓根沒想過用這個方法,私下看了看,還是給出一點點思考吧。若對您有幫助就好,沒有用就當是我補上了一篇博客吧。
EF 6.x和EF Core實現動態查詢
public static IEnumerable<dynamic> SqlQueryDynamic(this DbContext db, string Sql, params SqlParameter[] parameters) { using (var cmd = db.Database.Connection.CreateCommand()) { cmd.CommandText = Sql; if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } foreach (var p in parameters) { var dbParameter = cmd.CreateParameter(); dbParameter.DbType = p.DbType; dbParameter.ParameterName = p.ParameterName; dbParameter.Value = p.Value; cmd.Parameters.Add(dbParameter); } using (var dataReader = cmd.ExecuteReader()) { while (dataReader.Read()) { var row = new ExpandoObject() as IDictionary<string, object>; for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++) { row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]); } yield return row; } } } }
那么最終如上查詢后返回動態集合,我們該如何轉換為集合對象呢?我想都沒想如下直接先序列化然后反序列化,若您有更好的解決方案,請自行實現即可。
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var dynamicOrders = ctx.SqlQueryDynamic("select * from dbo.Orders"); var ordersJson = JsonConvert.SerializeObject(dynamicOrders); var orders = JsonConvert.DeserializeObject<List<Order>>(ordersJson); };
當然上述我只是簡單查詢了一個表,若您有多個表也是好使的,最后反序列化為不同的對象即可,未經測試,您可自行測試。
EF Core使用多個上下文實例池
有很多人無論是在EF 6.x還是在EF Core中一直以來都是使用一個上下文,但是不知我們是否有想過使用多個上下文呢?比如在電商項目中,對於產品相關操作我們可以使用產品上下文,對於加入購物車操作使用購物車上下文,對於訂單操作使用訂單上下文。這么做的好處是什么呢?我們可以將數據庫表也就說將實體拆分成不同的業務。至今我還沒看到有人這么做過,如果是我的話,至少我會這么做。
//Add DbContext var dbConnetionString = Configuration.GetConnectionString("DbConnection"); services.AddDbContextPool<ShopCartDbContext>(options => { options.UseSqlServer(dbConnetionString); }).AddDbContextPool<BookDbContext>(options => { options.UseSqlServer(dbConnetionString); }).AddDbContextPool<OrderDbContext>(options => { options.UseSqlServer(dbConnetionString); });
在EF Core 2.0中有了上下文實例池,類似於ADO.NET中的連接池一樣,但是這玩意你從表面理解那你就大錯特錯了,有關上下文實例池(從去年開始我着手寫了一本關於EF 6.x和EF Core的書籍最近會出版)實現本質,只能說它和ADO.NET中的連接池不是一樣的哦。那么如上述使用多個上下文實例池是否就一定好使呢?不好意思,這樣配置是錯誤的。但運行程序你會發現拋出類似如下異常:
Exception message: System.ArgumentException: Expression of type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MultiContext.Contexts.BContext]' cannot be used for constructor parameter of type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MultiContext.Contexts.AContext]' Parameter name: arguments[0] Stack trace: ...........
在此特性出來時大家都在歡呼能夠提高性能,對不起上下文實例池雖然可能在一定程度上提高性能,但是我只能講只能有可能的性能改進,如果你知道或者看過EF Core實現上下文實例池的原理,就明白了其實現的本質從而恍然大悟我所說的可能的性能上的改進是什么意思。至於為何不能注冊多個上下文實例池,我也是私下寫項目遇見的,具體請參看github:https://github.com/aspnet/EntityFrameworkCore/issues/9433。
總結
好了今天就到這里,沒有過多的解釋和敘述,上來就是直奔主題,最近思想放飛中,對寫博客慢慢失去了很大的興趣,偶爾感性中,待我滿血復活調節好心情再來和大家繼續分享技術,我一直在,一段時間沒寫博客可能是因為累了,又或者是私下在學習IdentityServer或者其他技術中,干咱這行的,除非轉行那就老老實實積累經驗和多學點技術吧,年輕不奮斗,那什么時候奮斗呢。今天說了啥,胡思亂想中,莫見怪。