简体   繁体   English

如何结合查询复杂对象的两个复杂查询?

[英]How to union two complex queries querying complex objects?

I am quite new to entity framework so I am confused now. 我对实体框架很陌生,所以我现在很困惑。 I have these two queries: 我有这两个问题:

var usersQuery =
            from role in this.dbContext.Set<Model.ApplicationRole>()
            join ru in dbContext.Set<Model.ApplicationRoleUser>() on role.Id equals ru.ApplicationRoleId into rus
            from ru in rus.DefaultIfEmpty()
            join user in dbContext.Set<Model.User>() on ru.UserId equals user.Id into users
            from user in users.DefaultIfEmpty()
            where
                (ru != null && ru.ApplicationId == application.Id)
             && (roleId == null || ru.ApplicationRoleId == roleId.Value)
            group role by user into grps

            select
                new RoleActor
                {
                    Actor =
                        new Actor
                        {
                            AccountName = grps.Key.AccountName,
                            DisplayName =
                                (grps.Key.DisplayName ?? string.Empty) != string.Empty
                                    ? grps.Key.DisplayName
                                    : grps.Key.CommonName,
                            DomainName = grps.Key.DomainName,
                            Email = grps.Key.Email ?? string.Empty,
                            CompanyCode = grps.Key.CompanyCode,
                            AdGuid = grps.Key.AdGuid,
                            CommonName = grps.Key.CommonName
                        },
                    Type = Model.ActorType.User,
                    RoleNames = grps.Select(role => role.Name).ToList()
                };

        var groupsQuery =
            from role in this.dbContext.Set<Model.ApplicationRole>()
            join rg in dbContext.Set<Model.ApplicationRoleGroup>() on role.Id equals rg.ApplicationRoleId into rgs
            from rg in rgs.DefaultIfEmpty()
            join @group in dbContext.Set<Model.Group>() on rg.GroupId equals @group.Id into groups
            from @group in groups.DefaultIfEmpty()
            where
                (rg != null && rg.ApplicationId == application.Id)
             && (roleId == null || rg.ApplicationRoleId == roleId.Value)
            group role by @group into grps
            select
                new RoleActor
                {
                    Actor =
                        new Actor
                        {
                            AccountName = grps.Key.AccountName,
                            DisplayName =
                                (grps.Key.DisplayName ?? string.Empty) != string.Empty
                                    ? grps.Key.DisplayName
                                    : grps.Key.CommonName,
                            DomainName = grps.Key.DomainName,
                            Email = string.Empty,
                            CompanyCode = string.Empty,
                            AdGuid = grps.Key.AdGuid,
                            CommonName = grps.Key.CommonName
                        },
                    Type = Model.ActorType.Group,
                    RoleNames = grps.Select(role => role.Name).ToList()
                };

I need to union these two queries. 我需要结合这两个查询。 But when I try to use extension method Union, I get exception: 但是当我尝试使用扩展方法Union时,我得到异常:

The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument. “Distinct”操作不能应用于指定参数的集合ResultType。 Parameter name: argument 参数名称:参数

I wanted to concat queries and then do something like: 我想连接查询然后执行以下操作:

queryConcatResult.GroupBy(x => x.Key).Select(x => x.FirstOrDefault())

However when I use method Concat, I get exception: 但是当我使用方法Concat时,我得到异常:

The nested query is not supported. 不支持嵌套查询。 Operation1='UnionAll' Operation2='MultiStreamNest' Operation1 ='UnionAll'Operation2 ='MultiStreamNest'

I will be grateful for any hint. 我会感激任何提示。

It's not possible (at least with EF) to perform union or concat of queries that contain nested collection (for instance the result of group by or RoleNames as in your case). 不可能(至少使用EF)执行包含嵌套集合的查询的并集或连接(例如,在您的情况下为group byRoleNames的结果)。

The solution is to remove the grouping from the base queries, create uniform projection, concat and then do the grouping. 解决方案是从基本查询中删除分组,创建统一投影,连接然后进行分组。

Something like this: 像这样的东西:

(1) (1)

var usersQuery =
    from user in dbContext.Set<Model.User>()
    join ru in dbContext.Set<Model.ApplicationRoleUser>() on user.Id equals ru.UserId
    join role in this.dbContext.Set<Model.ApplicationRole>() on ru.ApplicationRoleId equals role.Id
    where ru.ApplicationId == application.Id
        && (roleId == null || ru.ApplicationRoleId == roleId.Value)
    select new
    {
        Actor = new Actor
        {
            AccountName = user.AccountName,
            DisplayName = (user.DisplayName ?? "") != "" ? user.DisplayName : user.CommonName,
            DomainName = user.DomainName,
            Email = user.Email ?? "",
            CompanyCode = user.CompanyCode,
            AdGuid = user.AdGuid,
            CommonName = user.CommonName
        },
        Type = Model.ActorType.User,
        Role = role,
    };

(2) (2)

var groupsQuery =
    from @group in dbContext.Set<Model.Group>()
    join rg in dbContext.Set<Model.ApplicationRoleGroup>() on @group.Id equals rg.GroupId
    join role in this.dbContext.Set<Model.ApplicationRole>() on rg.ApplicationRoleId equals role.Id
    where rg.ApplicationId == application.Id
        && (roleId == null || rg.ApplicationRoleId == roleId.Value)
    select new
    {
        Actor = new Actor
        {
            AccountName = @group.AccountName,
            DisplayName = (@group.DisplayName ?? "") != "" ? @group.DisplayName : @group.CommonName,
            DomainName = @group.DomainName,
            Email = "",
            CompanyCode = "",
            AdGuid = @group.AdGuid,
            CommonName = @group.CommonName
        },
        Type = Model.ActorType.Group,
        Role = role,
    };

(3) (3)

var actorsQuery =
    from a in usersQuery.Concat(groupsQuery)
    group a by new { a.Actor, a.Type } into g
    select new RoleActor
    {
        Actor = g.Key.Actor,
        Type = g.Key.Type,
        RoleNames = g.Select(a => a.Role.Name).ToList()
    };

Side note: Although using string.Empty is a good programming practice, you'd better avoid it in EF queries because EF does not recognize it as constant and generates additional SQL query parameters. 旁注:尽管使用string.Empty是一种很好的编程习惯,但最好在EF查询中避免使用它,因为EF不会将其识别为常量并生成其他SQL查询参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM