链接到实体聚合方法替换

时间:2015-06-01 21:16:11

标签: entity-framework linq-to-entities entity-framework-6

看起来Linq to Entities不支持Aggregate方法。我需要将这个更大表达式的.Select(a => a.Permissions).Aggregate((a, b) => a | b)部分重写为Linq to Entities理解的内容。有可能吗?

也许我应该更好地解释一下我在做什么。我需要根据这些组织者的用户权限从数据库中获取组织者的集合。权限存储为位标志,并且是以下内容的组合:

  1. DefaultOrganizerPermissions - 每个管理器都有一些默认权限
  2. OwnerPermissions - 如果User是Organizer的所有者,则他还有一些其他权限
  3. UserPermisions - 可以手动分配用户以获得一些“管理员权限”
  4. RolePermissions - 用户可以是角色的成员,可以分配这些角色以获得组织者的其他权限。
  5. 所以我有一个带有以下签名的方法

    public IQueryable<Organizer> GetOrganizers(Person person, OrganizerPermissions requiredPermissions)

    并且里面有一个像这样的代码

    organizers = organizers.Where(o => ((
            // Default permissions
            DefaultOrganizerPermissions |
            // Owner permissions
            (o.OwnerId == person.Id ? OwnerOrganizerPermissions : 0) |
            // Personal permissions
            (o.AccessIdentifier.Accesses.FirstOrDefault(a => a.Accessor is PersonalAccessor && (a.Accessor as PersonalAccessor).PersonId == person.Id) != null ?
            (OrganizerPermissions)o.AccessIdentifier.Accesses.FirstOrDefault(a => a.Accessor is PersonalAccessor && (a.Accessor as PersonalAccessor).PersonId == person.Id).Permissions : 0) |
            // Role permissions
            (o.AccessIdentifier.Accesses.Any(a => a.Accessor is RoleAccessor && (a.Accessor as RoleAccessor).Role.RoleMembers.Any(rm=>rm.PersonId == person.Id)) ?
            (OrganizerPermissions)o.AccessIdentifier.Accesses.Where(a=> a.Accessor is RoleAccessor && (a.Accessor as RoleAccessor).Role.RoleMembers.Any(rm => rm.PersonId == person.Id)).Select(a=>a.Permissions).Aggregate((a, b) => a | b) : 0)
            ) & requiredPermissions) == requiredPermissions);
    

    简化它是这样的:

    organizers = organizers.Where(o => ((
            DefaultOrganizerPermissions |
            OwnerOrganizerPermissions |
            UserPermisions  |
            RolePermissions
            ) & requiredPermissions) == requiredPermissions);
    

    问题是用户可以是多个角色的成员,因此RolePermissions实际上是多个权限,我需要使用按位OR将其展平。但是,如果不支持Aggregate怎么办?

3 个答案:

答案 0 :(得分:1)

如果数据量不是非常大,您可以考虑在.ToList()语句之前调用Select(...)以将数据读入内存,然后执行聚合作为Linq to Objects

答案 1 :(得分:0)

如果权限可以为空,则可能需要插入
a.Permissions.GetValueOrDefault()
所以查询应该是
.Select(a =&gt; a.Permissions.GetValueOrDefault())。Aggregate((a,b)=&gt; a | b)

此外,如果EF提供程序不支持对SQL的聚合转换(此部分是提供程序特定的,因此它可以与一个DBMS一起使用但不能与不同的DBMS一起使用),则需要使用ToList()实现查询(如建议的那样) @sjager)。

修改
问题是EF提供程序不支持将聚合转换为SQL。

我不是SQL Server专家,无论如何你应该找到一个聚合函数(如SUM或AVG),它可以满足您的需要(按位OR)。在MySQL中是BIT_OR()。

如果它不存在则GAME OVER

如果存在,您可以查看SQL提供程序的SQL提供程序的源代码,并查看LINQ函数是否被翻译成该问题或提出另一个问题 -

答案 2 :(得分:0)

令人惊讶的是,我昨天遇到了完全相同的情况。 所以,正如@bubi所说,如果没有SQL服务器正确的聚合函数,那么就不可能

我解决这个问题的方法是 - 为每个角色创建一堆OR表达式组,每个组都与用户角色进行比较。之后,将所有“OR表达式组”与AND谓词连接。

E.g。如果用户具有0011枚举值,则需要为0001和0010标志创建OR谓词。 0001标志“OR组”看起来像

x=> x.Equals(0001) || x.Equals(0011) || x.Equals(0101)| || ..)

但绝对不推荐。