【问题标题】:Translate this Sql query into NHibernate Linq or Criteria?将此 Sql 查询翻译成 NHibernate Linq 或 Criteria?
【发布时间】:2011-02-01 18:29:42
【问题描述】:

我有一个安全架构,其中某些实体通过 SecureEntity 引用得到保护。 SecureEntity 有一个 RolePermissions 集合,每个 RolePermissions 都有一个 Allow 标志和一个 Priority。这个想法是将用户的角色与 SecureEntity 上的 RolePermissions 进行匹配。例如,用户可能被其最低优先级权限允许但被更高优先级权限拒绝,因此它是我们感兴趣的最高权限。在此示例中,我正在查询的根实体称为 ProcessCategory。

(SecureRoleId 是用户角色的匹配项;SecureRoleName 只是一个字符串描述。)

假设用户具有角色 (1,2) 并且 SecureEntity 具有 RolePermissions:

SecureRoleId = 1, Priority = 0, Allow = true
SecureRoleId = 2, Priority = 1, Allow = false

在这种情况下,不会选择实体。但如果用户只有角色 1,则将选择实体。当然,SecureEntity 可能包含一堆用户没有且不相关的其他角色。

下面的 sql 代码工作并执行此操作:“如果用户还拥有的最高优先级角色权限是 Allow=true,则选择实体”。因此,它基本上过滤用户自己的角色(IN 子句)的 RolePermission,按优先级排序,如果是 Allow,则采用最高的。

这是 Sql:

select pc.* from ProcessCategory pc
join SecureEntity se 
    join RolePermission rp on se.SecureEntityId = rp.SecureEntityId 
on pc.SecureEntityId = se.SecureEntityId
where rp.RolePermissionId = (select top 1 RolePermissionId 
                from RolePermission
                where Allow = 1
                and SecureEntityId = se.SecureEntityId
                and SecureRoleId in(0,1)
                order by Priority desc)

上面的 Sql 可能有另一种写法,但它可以满足我的需要。理想情况下,我想使用 NHibernate Linq 或 Criteria 来实现这一点。我花了几个小时试图让 Linq 工作,但由于内部连接到 RolePermission 的各种“无效操作”异常而失败。我对 ICriteria 或 MultiCriteria 没有太多经验,如果有人可以帮助我,我会很感兴趣。

请注意,对象的 Fluent 映射很简单:

 <some-entity>.References(x => x.SecureEntity) 

 SecureEntity.HasMany(x => x.RolePermissions).Not.Inverse();

【问题讨论】:

    标签: nhibernate linq-to-nhibernate


    【解决方案1】:

    好的。我无法使用 native NH Linq 让它工作,尽管这并不意味着它是不可能的。但是我查看了 Linq 的所有 NH 单元测试,但找不到任何等效的东西。

    为了让它工作,我创建了一个名为 UserHasPermission 的数据库函数,它可以完成以下所有操作:

    on pc.SecureEntityId = se.SecureEntityId
    where rp.RolePermissionId = (select top 1 RolePermissionId 
                from RolePermission
                where Allow = 1
                and SecureEntityId = se.SecureEntityId
                and SecureRoleId in(0,1)
                order by Priority desc)
    

    这适用于任何类型的安全实体。然后,我按照此页面中的说明将该函数映射为 NH Linq 函数:http://wordpress.primordialcode.com/index.php/2010/10/01/nhibernate-customize-linq-provider-user-defined-sql-functions/

    如果您按照这些说明进行操作,则必须在 C# 中创建一个与您的数据库具有相同签名的普通 LinqToObjects 扩展。然后,您可以像这样进行 NH Linq 查询:

    return base.Query<T>().Where(c => ((ISecureEntity)c)
                .SecureEntity.Id
                .UserHasPermissions(user.SecureRoleIdsCsv) == 1);
    

    我发现的唯一问题是我原来的 Sql 函数返回了一点,我将其映射到 NH 布尔类型。然而,这产生了一个非常奇怪的 sql,其中有几个“Where ''True'' = ''True''”子句在 Sql Server 中爆炸。所以我将结果更改为整数,一切正常。有点反直觉,但是...

    这样做让我可以透明地使用 Linq 处理我的所有查询,而不会影响现有代码,因为它会自动为每个查询添加安全检查。

    请注意,我查看了 Rhino Security 源代码,它使用了多个标准,对于我有限的 NH 知识,我无法理解。如果我使用 CreateCriteria 完成,我可以将它与 Linq 结合起来吗?

    • 上面链接中的说明并没有明确说明,当您创建自己的注册 Sql 函数的 Dialect 时,您必须确保在您的 NH 配置文件(或代码)中引用它,否则您会得到某种“未知类型”异常。

    【讨论】:

      猜你喜欢
      • 2012-08-27
      • 1970-01-01
      • 2019-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多