2017-06-18 147 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可能是一个更好的选择。

最后:你是否看到,因为正确使用复数和单数,查询更具可读性。将来需要由其他人实施更改时,犯的错误变化较小。