2017-06-18 191 views
0

我在EF中使用linq查詢特定屬性的問題。無法查詢集合的集合

概述,用戶具有關聯的角色。每個角色都有關聯組。我只是試圖獲取與用戶關聯的所有組的MAMUserGroup屬性。我可以很容易地使用.Include()獲得關聯角色,但是在向關聯的MAMUserGroups添加一個額外級別時遇到困難。

用戶模式:

public class User 
{ 
    [Display(Name = "SSO")] 
    [Required] 
    [StringLength(9, ErrorMessage = "SSO must be 9 numbers", MinimumLength = 9)] 
    public virtual string ID { get; set; } 

    [Display(Name = "First Name")] 
    [Required] 
    public string FirstName { get; set; } 

    [Display(Name = "Last Name")] 
    [Required] 
    public string LastName { get; set; } 

    [Display(Name = "MAM Roles")] 
    public ICollection<MAMRoleModel> MAMRoles { get; set; } 



} 

MAMRole型號:

public class MAMRoleModel 
{ 
    public int ID { get; set; } 

    public string Name { get; set; } 

    public ICollection<MAMUserGroupModels> MAMUserGroups { get; set; } 
} 

MAM組型號:

public class MAMUserGroupModels 
{ 
    public int ID { get; set; } 
    public string MAMUserGroup { get; set; } 
} 

我已經試過

foreach(var bar in user.MAMRoles) 
       { 
        foreach(var foo in bar.MAMUserGroups) 
        { 
         //do something 
        } 
       } 

但收到空引用錯誤。我也試過從haim770

var test = db.Users.Include(x => x.MAMRoles.Select(y=> y.MAMUserGroups)); 

但是MAMUserGroup是0的計數,所以它沒有看到引用。

+0

'yourDbSet.Include(user => user.MAMRoles.Select(role => role.MAMUserGroups))' – haim770

+0

顯示您嘗試過的方式,以及它在哪裏給您提供問題[mcve] – Nkosi

+0

haim770,我是使用此代碼獲得0個MAMUserGroups的計數。我去了,並驗證我的sql對象資源管理器中存在關係數據。 – rStackSharper

回答

0

我認爲問題的產生是因爲您沒有在實體框架中的一對多關係中將您的ICollection聲明爲虛擬。聲明ICollection虛擬將解決它

爲了防止未來的問題,考慮讓您的類更符合實體框架。這減少了各種屬性的使用。正確使用複數形式和單數形式可以提高查詢的可讀性,這有助於將來必須更改代碼的人員。

  • 主鍵「ID」不應該是虛擬
  • 在你一到許多使用上的一面虛擬的ICollection,並添加引用添加到一個和外鍵的許多方面
  • 考慮使用標準的命名約定。這有助於實體框架定義模型,而無需使用各種屬性來幫助它。
  • 如果您真的需要,只會偏離標準的命名約定。在這種情況下,爲主鍵,外鍵,一對多關係等添加屬性,或考慮使用流暢的API。

public class User 
{ 
    // Standard naming convention: automatic primary key 
    public string ID { get; set; } 

    // a user has many MAMRoles. 
    // standard naming convention: automatic one-to-many with proper foreign key 
    // declare the collection virtual! 
    public virtual ICollection<MAMRole> MAMRoles { get; set; } 
} 

public class MAMRole 
{ 
    // standard naming cause automatic primary key 
    public int ID { get; set; } 

    // a MAMRole belongs to one user (will automatically create foreign key) 
    // standard naming cause proper one-to-many with correct foreign key 
    public string UserId {get; set;} 
    public virtual User User {get; set;} 

    // A MamRole has many MAMUserGroupModels 
    // same one-to-many: 
    // again: don't forget to declare the collection virtual 
    public virtual ICollection<MAMUserGroupModel> MamUserGroupModels{ get; set; } 
} 

public class MAMUserGroupModel 
{ 
    // automatic primary key 
    public int ID {get; set;} 

    // a MAMUserGroupModel belongs to one MAMUser 
    // automatic foreign key 
    public int MAMUserId {get; set;} 
    public virtual MAMUser MAMUser {get; set;} 
} 

順便說一下。實體框架知道,只要您在IQueryable中使用它,就需要獲取屬性的值。只有當你想選擇屬性值並將它們存入本地內存時,你才需要使用Include。這使得查詢效率更高,因爲只選擇使用的值。

所以,如果你只想要做的東西MamUserGroupMamUserGroupModel內,不包括任何東西:

在嬰兒的步驟:

IQueryable<NamRole> mamRolesOfAllUsers = myDbContext.Users 
    .SelectMany(user => user.MamRoles); 
IQueryable<MamRoleModel> mamUserGroupModelsOfAllUsers = mamRolesOfAllUsers 
    .SelectMany(mamRole => mamRole.MamUserGroupModels); 
IQueryable<string> mamUserGroups = mamUserGroupModelsOfAllUsers 
    .Select(mamUserGroupModel => mamUserGroupModeModel.MamUserGroup; 

或者在一個聲明中

IQueryable<string> mamUserGroups = myDbContext.Users 
    .SelectMany(user => user.MamRoles) 
    .SelectMany(mamRole => mamRole.MamUserGroupModels) 
    .Select(mamUserGroupModel => mamUserGroupModel.MamUserGroup); 

請注意,直到知道我還沒有與數據庫溝通。我只創建了查詢的表達式。一旦枚舉開始查詢將做到:

foreach(var userGroup in mamUserGroups) 
{ 
    ... 
} 

注意使用SelectMany代替Select。無論何時收藏藏品,請使用SelectMany製作一個藏品。如果你發現自己在foreach中做了一個foreach,這很好地表明SelectMany可能是一個更好的選擇。

最後:你是否看到,因爲正確使用複數和單數,查詢更具可讀性。將來需要由其他人實施更改時,犯的錯誤變化較小。