EF Core 三 、 騷操作 (導航屬性,記憶體查詢...)
阿新 • • 發佈:2020-12-26
# 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