c# - 如何联合查询复杂对象的两个复杂查询?

标签 c# sql .net entity-framework linq

我对 Entity Framework 很陌生,所以我现在很困惑。我有这两个问题:

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()
                };

我需要合并这两个查询。但是当我尝试使用扩展方法 Union 时,出现异常:

The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument. Parameter name: argument

我想连接查询然后做类似的事情:

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

但是当我使用 Concat 方法时,出现异常:

The nested query is not supported. Operation1='UnionAll' Operation2='MultiStreamNest'

如有任何提示,我将不胜感激。

最佳答案

不可能(至少对于 EF)执行包含嵌套集合的查询的联合或连接(例如 group byRoleNames 的结果,如您例)。

解决方案是从基本查询中删除分组,创建统一投影,连接然后进行分组。

像这样:

(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)

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)

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()
    };

旁注:虽然使用 string.Empty 是一个很好的编程习惯,但您最好避免在 EF 查询中使用它,因为 EF 不会将其识别为常量并生成额外的 SQL 查询参数。

关于c# - 如何联合查询复杂对象的两个复杂查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39634302/

相关文章:

c# - 有一个带有 ShowInTaskbar、Topmost 的窗口,还有一个通知区域图标

mysql - 我可以使用 VARCHAR 作为主键吗?

c# - 回调接口(interface)合约

c# - 将 ASP.NET 应用程序移植到 Linux 下的 Mono/Apache

c# - 在 C# 中,我可以在编译类型中检查一个类是否可序列化吗?

c# - 代码中的 Colgroup 标记但在查看源代码或调试器工具中缺失

c# - C# 中计算另一个字符串中字符串出现次数的最快方法

c# - 使用 C# Access 数据库

mysql - SQL SELECT COUNT GROUP BY - 错误

sql - 如何使用 Powershell Restore-SqlDatabase cmdlet 可靠地覆盖现有数据库