Asp.net-Mvc

使用實體框架我只想包含第一個子對象而不是子的子(子的子)

  • May 12, 2015

使用實體框架我只想包含第一級子對象而不是子對象

我有這兩個類:

public class BusinessesTBL
{
   public string ID { get; set; }
   public string FirstName { get; set; }
   public string lastName { get; set; }

   public ICollection<OffersTBL> OffersTBLs { get; set; }
}

public class OffersTBL 
{
   public int ID { get; set; }
   public string Name { get; set; }

   public int CatId { get; set; }

   public string BusinessesTBLID { get; set; }
   public virtual BusinessesTBL BusinessesTBLs { get; set; }
}

當我嘗試根據 CatId 欄位提供所有優惠時,我還需要返回 BusinessesTBLs,但該方法還會根據每個 BusinessesTBL obj 再次返回優惠,我的程式碼是:

public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
   db.OffersTBLs.Include(s => s.BusinessesTBLs);
}

您可以在以下位置看到錯誤的結果: http: //mycustom.azurewebsites.net/api/OffersApi/GetOffersTBLsCat/4

如您所見,它返回每個業務對像下的所有報價,而每個報價下的業務對象,我只想返回帶有其業務對象的報價,而不返回業務對像下的報價。

有人可以幫忙嗎?

一個downvote讓這個答案重新引起了我的注意(謝謝)。我現在看到其中很大一部分是胡說八道。

果然,死循環的原因是關係修復。但是你不能阻止 EF 這樣做。即使在使用時AsNoTracking,EF 也會在一個查詢中具體化的對像中執行關係修復。因此,您的查詢Include將導致完全填充的導航屬性OffersTBLsBusinessesTBLs.

消息很簡單:如果您不希望結果中出現這些引用循環,則必須投影到視圖模型或 DTO 類,如其他答案之一。在我看來,在進行序列化時,另一種不太吸引人的方法是將序列化程序配置為忽略引用循環。另一個不太吸引人的替代方法是單獨獲取對象AsNoTracking並自己有選擇地填充導航屬性。


原答案:

發生這種情況是因為 Entity Framework 執行關係修復,這是在上下文中存在屬於那裡的對象時自動填充導航屬性的過程。因此,使用循環引用,即使禁用延遲載入,您也可以無休止地向下鑽取導航屬性。Json 序列化程序正是這樣做的(但顯然它被指示處理循環引用,因此它不會陷入無限循環)。

訣竅是防止關係修復發生。關係修復依賴於上下文ChangeTracker,它記憶體對像以跟踪它們的更改和關聯。但是,如果沒有什麼可跟踪的,就沒有什麼可修復的。您可以通過呼叫停止跟踪AsNoTracking()

db.OffersTBLs.Include(s => s.BusinessesTBLs)
            .AsNoTracking()

如果除此之外您還禁用了上下文的延遲載入(通過設置contextConfiguration.LazyLoadingEnabled = false),您將看到僅OffersTBL.BusinessesTBLs填充在 Json 字元串中並且BusinessesTBL.OffersTBLs是空數組。

一個好處是AsNoTracking()提高了性能,因為更改跟踪器並不忙於跟踪 EF 實現的所有對象。事實上,您應該始終在斷開連接的環境中使用它。

引用自:https://stackoverflow.com/questions/30186315