2016-01-14 56 views
1

檢索具有循環引用的實體時遇到問題。我的實體導航屬性不是延遲加載,所以我希望它們返回null,除非明確包含在查詢中,但是我發現當兩個實體之間存在循環引用時,情況並非如此,而是遞歸層次結構返回。防止實體框架中的循環導航屬性的自動填充

例如,假設我們有兩個實體UserEntityPostEntity。 A UserEntity可能有許多帖子,但帖子只能有一個UserEntity。所以,配置如下:

// UserEntity configuration 
HasMany(u => u.Posts) 
    .WithRequired(p => p.User); 

如果我查詢數據庫爲任何一個UserEntityPostEntity而不對各自PostsUser導航屬性使用Include(),如所預期的導航屬性爲空。

但是,如果我查詢了UserEntity,包括其PostEntity S,一個圓形的層級返回,儘管我從來沒有要求將PostEntity.User導航屬性填充:

using (var db = new MyDbContext()) 
{ 
    var user = await db.Users 
    .Include(u => u.Posts) 
    .SingleOrDefaultAsync(u => u.ID == 0); 

    // The [UserEntity] contains a list of [PostEntitiy]s 
    // each with the [UserEntity] each with a list of [PostEntitiy]s... 
    //  and so on. 
} 

這是不是太多麻煩,但是當PostEntity個列表檢索及其UserEntity s的包含事情就變得很奇怪:

using (var db = new MyDbContext()) 
{ 
    var posts = await db.Posts 
    .Include(p => p.User) 
    .SingleOrDefaultAsync(p => p.ID == 0); 

    // This throws a [System.InvalidOperationException]: 
    // "Sequence contains more than one element" 
    // How can this be? The ID is unique. 

    var posts = await db.Posts 
    .Include(p => p.User) 
    .Where(p => p.ID == 0) 
    .ToListAsync(); 

    // This returns several copies of the PostEntity 
    // which should be unique in the database. Is 
    // this a side effect of the circular reference? 
} 

顯然擺脫循環引用的可以解決這個問題,但如果可能的話,爲什麼保持它有益呢有幾個原因。 爲什麼EntityFramework返回這個循環層次結構,儘管只有一個單一的單向關係請求Include(),並且爲什麼在包含它們的UserEntity時返回多個PostEntity

+0

您是將主鍵映射到屬性還是流利的API?此外,循環引用,你注意到它在代碼或調試器? –

+0

是的,我爲我的所有配置使用流暢的API,主鍵已正確映射。數據庫首先是代碼,而不是這個循環引用問題,它完美地工作。 循環引用是由設計,但我從來沒有打算檢索遞歸hirarchy - 即我想要它的用戶的職位,或用戶的所有職位。返回的結果是遞歸的用戶帖子,用戶的帖子與帖子...等。這在調試器中是可見的,似乎也會影響查詢結果。 –

回答

2

您可以嘗試將您的實體投影到DTO中以解決此問題。將projection用於某些沒有此類引用的類型,並避免出現異常。

換句話說,拿起只是你從EF模型需要,不增加其嵌套複雜類型也有回指向同一個對象的屬性,從而創建循環引用

using (var db = new MyDbContext()) 
{ 
    var posts = db.Posts 
     .Include(p => p.User) 
     .Where(p => p.ID == 0) 
     .Select(p => new PostsDTO 
     { 
      Name = p.Name, 
      Username = p.User.Username 
     }); 
} 
字段屬性
+0

使用DTO(或者只是投影到動態對象)確實解決了我一直存在的問題,但是我正在處理相當大,複雜的實體以及許多不同的查詢。有沒有辦法簡化這個過程,最好是避免手動將值映射到屬性?否則,我正在潛心研究幾小時的工作。 –

+0

儘管這可能很痛苦,但我認爲將您的域實體映射到DTO是有益的。首先,您沒有這些循環引用問題,其次,您不會將域對象公開給業務/表示層。如果你的地圖很棘手(或者單調乏味的映射),可以考慮使用[automapper iqueryable extensions](https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions)爲你做這些預測。 – KevDev