簡體   English   中英

如何使EF Core Include()不跟蹤實體?

[英]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.parentnull 實體對象或DTO並非如此,序列化之后就是這種情況。 因為我為序列化程序設置了ReferenceLoopHandling.Ignore

這解決了我的應用程序所有問題,但我的api似乎不完整。 返回的JSON似乎丟失了某些內容(也許只是我,IDK)。

歸根結底,從長遠來看,我考慮在不同情況下使用多個具有相同對象類型的DTO或在api中返回id字段以確保完整性。

感謝所有人的評論和答復。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM