2011-10-10 89 views
0

我會開始說這可能不是概念上正確的,所以我也會發布我的問題,所以如果有人可以幫助解決底層問題,我不需要去做這個。創建一個'多對多'映射表的實體代碼首先

這是我的模型的簡化版本。

public class MenuItem 
{ 
    public int MenuItemId { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Department> Departments { get; set; } 

    private ICollection<MenuSecurityItem> _menuSecurityItems; 
    public virtual ICollection<MenuSecurityItem> MenuSecurityItems 
    { 
     get { return _menuSecurityItems ?? (_menuSecurityItems = new HashSet<MenuSecurityItem>()); } 
     set { _menuSecurityItems = value; } 
    } 
} 

public class Department 
{ 
    public int DepartmentId { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<MenuItem> MenuItems { get; set; } 
} 

我的根本問題是,我要選擇屬於某個部門(部門與DepartmentID的= 1爲了討論),也包括所有MenuSecurityItems所有的MenuItems。

由於MenuItems導航集合是ICollection類型的,並且不支持Include(),所以我無法包含()MenuSecurityItems。這似乎也不起作用Department.MenuItems.AsQueryable().Include(m => m.MenuSecurityItems)

我「解決」這個問題的方式是爲Code First創建的多對多映射表創建一個實體。

public class DepartmentMenuItems 
{ 
    [Key, Column(Order = 0)] 
    public int Department_DepartmentId { get; set; } 
    [Key, Column(Order = 1)] 
    public int MenuItem_MenuItemId { get; set; } 
} 

然後我能夠通過映射表來參加像這樣。 (MenuDB是我的DBContext)

var query = from mItems in MenuDb.MenuItems 
      join depmItems in MenuDb.DepartmentMenuItems on mItems.MenuItemId equals depmItems.MenuItem_MenuItemId 
      join dep in MenuDb.Departments on depmItems.Department_DepartmentId equals dep.DepartmentId 
      where dep.DepartmentId == 1 
      select mItems; 

這實際上適用於特定的查詢......但它打破了我的導航集合。現在,EF4.1在嘗試使用導航集合時試圖找到名爲DepartmentMenuItems1的對象,因此引發了異常。

如果有人可以幫我解決原始問題或者我現在用映射表實體創建的問題,那麼將不勝感激。

回答

1

嵌套集合的預先加載的工作原理是在外部收集使用Select要包括:

var department = context.Departments 
    .Include(d => d.MenuItems.Select(m => m.MenuSecurityItems)) 
    .Single(d => d.DepartmentId == 1); 

你也可以使用一個虛線路徑以字符串形式的IncludeInclude("MenuItems.MenuSecurityItems")


編輯:你的問題在評論如何申請一個過濾器的MenuItems集合加載:

很抱歉,您不能使用Include的熱門負載進行篩選。你的具體情況最好的解決方法(在這裏你只加載一個單一的部門)是放棄渴望加載以及如何利用explicite裝載代替:

// 1st roundtrip to DB: load department without navigation properties 
var department = context.Departments 
    .Single(d => d.DepartmentId == 1); 

// 2nd roundtrip to DB: load filtered MenuItems including MenuSecurityItems 
context.Entry(department).Collection(d => d.MenuItems).Query() 
    .Include(m => m.MenuSecurityItems) 
    .Where(m => m.Active) 
    .Load(); 

這需要兩個往返到數據庫和兩個查詢,但它是在最乾淨的方法我的意見,其實只是加載你需要的數據。

其他解決方法是:1)稍後在內存中應用過濾器(但必須首先從數據庫加載整個集合,然後才能過濾)或2)使用投影。這是這裏解釋(第二和第三點):

EF 4.1 code-first: How to order navigation properties when using Include and/or Select methods?

在這個答案的例子是訂購,但同樣適用於過濾(只是Where替換代碼片段OrderBy)。

+0

謝謝,這似乎已經訣竅 –

+0

如果MenuItem類包含一個布爾活動屬性,如何添加一個where子句的上述查詢? var department = context.Departments.Include(d => d.MenuItems.Where(m => m.Active).Select(m => m.MenuSecurityItems))。Single(d => d.DepartmentId == 1)doesn不工作 –

+0

@Matt:看我上面的編輯。 – Slauma

相關問題