实体框架 6 在 LINQ 查询的父对象中添加嵌套子对象

Tox*_*xic 1 linq entity-framework-6 .net-core

我正在开发 .NET Core 应用程序;实体框架 6

我需要在 LINQ 查询而不是 lambda 表达式中添加作为集合的子对象

用户 - 父实体

public class UserDataModel
{
    public UserDataModel()
    {
        this.Roles = new HashSet<UserRoleDataModel>();
    }

    public Guid Id { get; set; }

    public Guid IdentityProviderID {get; set;}  

    public ICollection<UserRoleDataModel> Roles { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

子实体

public class UserRoleDataModel
{
    public Guid UserId { get; set; }

    public UserDataModel Users { get; set; }

    public Guid RoleId { get; set; }

    public RoleDataModel Roles { get; set; }


}
Run Code Online (Sandbox Code Playgroud)

LINQ

var uu = (from _user in db.Users
            join _userRole in db.UserRoles on _user.Id equals _userRole.UserId
             where _user.IdentityProviderID == AureID
             select new {
                        _user,
                        _userRole 
                        }
Run Code Online (Sandbox Code Playgroud)

这是我达到的目标,但角色是集合,其中选择角色分离的子查询是 IQueryable 因此抛出转换/转换错误

 var uu = (from _user in db.Users
                          where _user.IdentityProviderID == AureID
                          select new UserDataModel
                          {
                              Id = _user.Id,
                              IdentityProviderID = _user.IdentityProviderID,
                              Roles = (from b in db.UserRoles where b.UserId == userId select b)
                          }
                         ).ToList();
Run Code Online (Sandbox Code Playgroud)

Har*_*lse 5

在最后评论后添加

似乎您在 UserData 和 UserRoles 之间存在真正的一对多关系:每个 UserData 都有零个或多个 UserRoles,每个 UserRole 只属于一个 UserData。

您的类定义偏离了实体框架代码优先约定。如果您将类配置为标准的实体框架一对多关系,实体框架会识别出您打算设计一对多并自动知道查询中何时需要连接。重新考虑重写你的类:

class UserDataModel
{
    public GUID Id {get; set;}   // primary key

    // every UserDataModel has zero or more UserRoleDataModels:
    public virtual ICollection<UserRoleDataModel> UserRoleDataModels {get; set;}

    ... // other properties
}
class UserRoleDataModel
{
    public GUID Id {get; set;}   // primary key

    // every UserDataRoleModel belongs to exactly one UserDataModel
    // using foreign key:
    public Guid UserDataModelId {get; set;}
    public virtual UserDataModel UserDataModel {get; set;}

    ... // other properties
}
Run Code Online (Sandbox Code Playgroud)

最重要的变化是我在您的 UserDataModel 和您的 UserDataRoleModels 之间建立了虚拟引用。我更改了外键的名称,因此实体框架无需任何属性/流畅的 API 即可知道您打算配置一对多。

回到你的问题

给定 UserDataModel 的 Id,给我 UserDataModel 及其所有 UserDataRoleModels

在您使用适当的虚拟 ICollection 重写类之后,您的查询将很简单:

var result = myDbContext.Users
    .Where(user => user.Id == AureId)
    .Select( user => new
    {
        User = user,
        Roles = user.Roles.ToList(),
    });
Run Code Online (Sandbox Code Playgroud)

此要求的缺点是您倾向于检索大量数据。查询数据库时较慢的部分之一是将查询的数据传输到本地进程。因此,最好不要获取比您想要的更多的数据。

您计划使用完整的 UserRole 对象查询完整的 UserData。如果您获取的 UserData 具有 Id XYZ,并且它有 50 个 UserRole 对象,那么它的每个 UserRole 对象都将具有一个值为 XYZ 的 UserDataId,因此传输它的次数是需要的 50 倍。

因此,我建议您仅传输您实际计划使用的数据:

 var result = myDbContext.Users
    .Where(user => user.Id == AureId)
    .Select( user => new
    {
        // from the user take only the data you plan to use
        Id = user.Id, // probably not, you know that it is AureId
        Name = user.Name,
        ... // other user properties you plan to use

        UserRoles = user.UserRoleDataModels.Select(roleData => new
        {
             // again: only the role data you plan to use
             Name = roleData.Name,
             Type = roleData.Type,
             ... // other properties

             // certainly not this one:
             UserDataId = roleData.UserDataId,
        })
        .ToList(),
    });
Run Code Online (Sandbox Code Playgroud)

这样您的查询会更快,您将只获取您想要的数据,您可以根据您的需要更改字段的名称,并且您可以根据需要添加由 UserData 中的值组成的新值

由于您的虚拟 ICollection,您不需要执行连接。实体框架了解您的一对多关系,并了解您对 ICollection 的使用应导致内部联接,然后是 Group By

总结:如果您认为您需要在实体框架中加入,请三思,您可能可以通过使用 ICollection 或对父项的引用来更简单地做到这一点

评论后补充

如果我们添加角色有定义表,我如何添加进一步的嵌套对象。

我不确定这意味着什么。我想你的意思是:如果一个角色有一个定义表怎么办,或者如果一个角色有零个或多个定义表怎么办。

class UserRoleDataModel
{
    public GUID Id {get; set;}   // primary key

    // every UserDataRoleModel belongs to exactly one UserDataModel
    // using foreign key:
    public Guid UserDataModelId {get; set;}
    public virtual UserDataModel UserDataModel {get; set;}

    // every role has exactly one DefinitionTable:
    public DefinitionTable DefinitionTable {get; set'}
}

 var result = myDbContext.Users
    .Where(user => user.Id == AureId)
    .Select( user => new
    {
        // from the user take only the data you plan to use
        ...

        UserRoles = user.UserRoleDataModels
           .Where(role => role... == ...)
           .Select(role => new
           {
               RoleDefinition = role.RoleDefinitiona,
               ...
           }),
    });
Run Code Online (Sandbox Code Playgroud)

如果您的角色有零个或多个角色定义,请执行与用户和角色相同的操作:添加虚拟 ICollection 并添加虚拟引用和外键,并在 Select 语句中使用集合。