1. 程式人生 > >EF Core 三 、 騷操作 (導航屬性,記憶體查詢...)

EF Core 三 、 騷操作 (導航屬性,記憶體查詢...)

# EF Core 高階操作 >本文之前,大家已經閱讀了前面的系列文件,對其有了大概的瞭解 我們來看下EF Core中的一些常見高階操作,來豐富我們業務實現,從而擁有更多的實現選擇 ## 1.EF 記憶體查詢 what?我們的ef不是直接連線資料庫嗎?我們查詢的主體肯定是資料庫啊,哪裡來的記憶體呢? **1.所有的資料操作都有過程,並非操作直接會響應到資料庫 2.並非所有的操作都每次提交,會存在快取收集階段,批量提交機制** 描述下業務場景,我們存在一個業務,需要儲存一張表,然後還需要對儲存表資料做一些關聯業務處理?我們可能會將方法拆分,首先處理資料儲存,然後再根據資料去處理業務 直接看下程式碼 ``` C# public static void Query_記憶體查詢()         {             TestTable newTable = new TestTable();             newTable.Id = 10;             newTable.Name = "測試資料";             using (MyDbContext dbContext = new MyDbContext())             {                 dbContext.Add(newTable);                 Query_記憶體查詢_關聯業務處理(dbContext); dbContext.SaveChanges();             }         }         private static void Query_記憶體查詢_關聯業務處理(MyDbContext dbContext)         {             var entity = dbContext.TestTables.FirstOrDefault(p => p.Id == 10);             //處理業務邏輯             //...         } ``` 程式碼執行效果: ![](https://img2020.cnblogs.com/blog/591768/202012/591768-20201226152407885-1815775376.png) 發現並沒有將資料查詢出來,因為預設會查詢資料庫資料,此時資料還未提交,所以無法查詢。但是也可以將實體資料傳入到依賴方法啊,這樣可以解決,但是如果關聯實體多,來回傳遞麻煩,所以這不是最佳解 **EF Core的快取查詢**,前面文章已經提到,EF Core會將所有的改動儲存到本地的快取區,等待一起提交,並隨即提供了基於快取查詢的方法,我們來驗證下 ``` C# public static void Query_記憶體查詢() { TestTable newTable = new TestTable(); newTable.Id = 10; newTable.Name = "測試資料"; using (MyDbContext dbContext = new MyDbContext()) { dbContext.Add(newTable); Query_記憶體查詢_關聯業務處理(dbContext); } } private static void Query_記憶體查詢_關聯業務處理(MyDbContext dbContext) { var entity = dbContext.TestTables.FirstOrDefault(p => p.Id == 10); //處理業務邏輯 //... var entity2 = dbContext.TestTables.Find(10); //處理業務邏輯 //... } ``` 程式碼執行效果: ![](https://img2020.cnblogs.com/blog/591768/202012/591768-20201226152518051-2044901741.png) 可以看到我們已經能夠查詢到未提交的資料了,但是也有必須的前提 **1.必須使用ID查詢**,這點我們下面來分析 **2.必須保證在同一上下文中**,這點通過我們前面文章分析,快取維護都是基於上下文維護,所以無法跨上下文來實現快取資料查詢 直接看原始碼,通過原始碼檢視,分析得到通過Find()方法呼叫StateManager.FindIdentityMap(IKey key)方法 ``` C# private IIdentityMap FindIdentityMap(IKey key) { if (_identityMap0 == null || key == null) { return null; } if (_identityMap0.Key == key) { return _identityMap0; } if (_identityMap1 == null) { return null; } if (_identityMap1.Key == key) { return _identityMap1; } return _identityMaps == null || !_identityMaps.TryGetValue(key, out var identityMap) ? null : identityMap; } ``` 這裡就是對_identityMaps集合進行查詢,那這個集合是什麼時候有資料呢?為何新增的資料會在?看下DBContext.Add方法 DbContext.Add=>InternalEntityEntry.SetEntityState=> StateManager.StartTracking(this)=>StateManager.GetOrCreateIdentityMap 核心程式碼: ``` C# if (!_identityMaps.TryGetValue(key, out var identityMap)) { identityMap = key.GetIdentityMapFactory()(SensitiveLoggingEnabled); _identityMaps[key] = identityMap; } ``` 會將當前實體放入集合中,如果集合中沒有查詢到,那就會執行資料庫查詢命令 ## 2.導航屬性 **通過一個實體的屬性成員,可以定位到與之有關聯的實體,這就是導航的用途了** 業務的發生永遠不會堆積在單表業務上,可能會衍生多個關聯業務表上,那在這種場景下,我們就需要導航屬性,還是以示例入手 首先,我們需要兩個關聯實體,來看下實體 ``` C# [Table("TestTable")] public class TestTable : EntityBase { [Key] public int Id { get; set; } public string Name { get; set; } public ICo