我在EF中使用linq查询特定属性时遇到了问题。
要概述,用户具有关联角色。每个角色都有关联组。我只是试图获取与用户关联的所有组的MAMUserGroup属性。我可以轻松地将关联角色与.Include()联系起来,但是无法将一个额外级别转到关联的MAMUserGroups。
用户模型:
<?php
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "save" && !empty($_REQUEST["elem"])){
$data = json_decode(file_get_contents("data.json"), true);
$data[0]["items"][] = $_REQUEST["elem"];
file_put_contents("data.json", json_encode($data));
}
?>
MAMRole模型:
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; }
}
MAM Group模型:
public class MAMRoleModel
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<MAMUserGroupModels> MAMUserGroups { get; set; }
}
我已经尝试了
public class MAMUserGroupModels
{
public int ID { get; set; }
public string MAMUserGroup { get; set; }
}
但得到了空引用错误。我也刚从haim770尝试
foreach(var bar in user.MAMRoles)
{
foreach(var foo in bar.MAMUserGroups)
{
//do something
}
}
但是MAMUserGroup的计数为0,所以它没有看到引用。
答案 0 :(得分:0)
我认为问题出现是因为你没有在实体框架中将一对多关系中的ICollection声明为虚拟。声明ICollection虚拟将解决它
为了防止将来出现问题,请考虑使您的类更符合实体框架。这减少了各种属性的使用。正确使用复数和单数可以提高查询的可读性,从而帮助那些必须在将来更改代码的人。
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
。这使得查询更有效,因为只选择了使用的值。
因此,如果您只想对MamUserGroup
内的MamUserGroupModel
执行某些操作,请不要包含任何内容:
在婴儿步骤中:
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
可能是更好的选择。
最后:你是否看到,由于正确使用复数和单数,查询更具可读性。如果将来有人在实施变更时犯错误,可以减少更改。