[英]How to make EF Core Include() not keep track of entities?
TLDR :我想知道是否可以在EF核心中的單個查詢中對一個實體類型使用不同的“包含邏輯”。
編輯 :明確一點,我在標題中說過跟蹤實體,因為我認為這就是EF所做的事情,但是.AsNoTracking()
在此之前沒有任何用處,而沒有任何人提出建議。
當前的問題在於一個相對較小的React應用程序,該應用程序以ASP.NET Core Web API應用程序為后盾。 我想要完成的是,當我調用api/parents
,我希望應用程序給我一個像這樣的json:
[
{
"id": "parentid1",
"extraProperty": "value",
"children": [
{
"id": "childid1",
"parent": {
"id": "parentid1",
"extraProperty": "value"
}
}
]
}
]
我的設置如下所示:
EF查詢 :
(from p in _context.Parents
select p)
.Include(p => p.Children)
.ThenInclude(c => c.Parent)
.ToList();
之后,我將實體映射到dto的AutoMapper進行了很多操作。 我還為該應用程序使用了默認的Json序列化器(Newtonsoft)。 使用SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore
配置。
通過此設置,api調用將返回以下響應:
[
{
"id": "parentid1",
"extraProperty": "value",
"children": [
{
"id": "childid1"
}
]
}
]
正如您所看到的,“忽略”了父級的自我引用。
我想到的解決方案是,我應該配置Newtonsoft以“序列化”參考循環,然后嘗試了一下。 並拋出異常,因為上面提供的EF查詢返回的實體列表如下所示:
[
{
"id": "parentid1",
"extraProperty": "value",
"children": [
{
"id": "childid1",
"parent": {
"id": "parentid1",
"extraProperty": "value",
"children": [
{
"id": "childid1",
"parent": {
"id": "parentid1",
"extraProperty": "value"
...
}
}
]
}
}
]
}
]
如果查看我的Include調用,它會明確表示對於我的子對象,我只想要父對象,而在該父對象中沒有其他引用。
盡我所能,EF在遇到該查詢的任何父對象時會使用初始設置.Include(child).ThenInclude(parent)
。 因此,當它在Child
對象中找到Parent
對象時,它使用.Include(child).ThenInclude(parent)
而不是不使用.Include(child).ThenInclude(parent)
在ThenInclude
之后沒有任何包含.Include(child).ThenInclude(parent)
。
如果不想,我不想通過使用映射器或序列化器的破解來解決此問題。 我想知道我所尋找的是否可能:在單個查詢中為一個實體類型使用不同的“包含邏輯”。
從ThenInclude(parent)
開始,那么ThenInclude(parent)
調用是多余的-物化的子級將已經填充了其Parent
屬性。 您需要按照第一個注釋中的@IvanStoev定制序列化。
另一種方法是按父級查詢子級,然后投影所需的結果:
var parents = _context.Children
.Include( c => c.Parent )
.GroupBy( c => c.Parent )
.ToArray()
.Select( g =>
{
// assign children to g.Key (the parent object)
g.Key.Children = g.ToArray(); // I don't know type of `Children` property
// select parent
return g.Key;
} );
我決定從最前端解決問題,因為其他解決方案對我不起作用。 為了將來參考,我將發布我的旅程:
EF
最初,在數據訪問層解決問題似乎是合乎邏輯的,因為我只是錯過了一個非常基本的東西。 我意識到在評論后采取這種方式是不合邏輯的。 基本上,當您從EF獲取實體並且您的對象具有引用時,每次您擁有一個以上對象時,它們都是同一對象(通過引用而不是值)。 因此,期望它們中包含不同的數據(在我的情況下,其中一個具有一些細節,而另一個則沒有)是不合邏輯的。
之后,我想也許我可以在映射階段解決此問題。 我嘗試針對不同的場景進行不同的配置文件/配置,但它變得非常難看。 然后,我想也許只使用一個Profile並執行AfterMap()
邏輯就可以了(最初加載所有數據,然后去除不需要的數據)。 但是,除非您做一些丑陋的事情,否則適用相同的原理。 AutoMapper還會保留引用,因此在修改child.Parent
對象時,原始的Parent也將被修改。 我本來可以使用克隆,也可以做一些其他的技巧,但就像我說的那樣,這在我看來很難看。
現在,我正在React應用程序上手動完成任務。 當我從服務器獲取數據時,
parent.children.forEach(c => c.parent = parent);
通常請記住, parent.children.parent
為null
。 實體對象或DTO並非如此,序列化之后就是這種情況。 因為我為序列化程序設置了ReferenceLoopHandling.Ignore
。
這解決了我的應用程序所有問題,但我的api似乎不完整。 返回的JSON似乎丟失了某些內容(也許只是我,IDK)。
歸根結底,從長遠來看,我考慮在不同情況下使用多個具有相同對象類型的DTO或在api中返回id字段以確保完整性。
感謝所有人的評論和答復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.