简体   繁体   English

将此SQL查询转换为NHibernate Linq或Criteria?

[英]Translate this Sql query into NHibernate Linq or Criteria?

I have a security schema where certain entities are secured by having a SecureEntity reference. 我有一个安全模式,其中某些实体通过具有SecureEntity引用来保护。 A SecureEntity has a collection of RolePermissions, each of which has an Allow flag and a Priority. SecureEntity具有RolePermissions的集合,每个角色都有一个Allow标志和一个Priority。 The idea is to match the user's roles against the RolePermissions on the SecureEntity. 这个想法是将用户的角色与SecureEntity上的RolePermissions进行匹配。 For example, a user may be allowed by their lowest priority permission but denied by a higher one, so it is the highest one that we are interested in. In this example the root entity I am querying is called ProcessCategory. 例如,一个用户可能会被其最低优先级权限所允许,但被较高优先级的权限所拒绝,因此它是我们感兴趣的最高权限。在此示例中,我要查询的根实体称为ProcessCategory。

架构图

(SecureRoleId is the match for the user's role; SecureRoleName is just a string description.) (SecureRoleId是用户角色的匹配项; SecureRoleName只是字符串描述。)

Assume a user has roles (1,2) and the SecureEntity has RolePermissions: 假设用户具有角色(1,2),并且SecureEntity具有RolePermissions:

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

In this case the entity would not be selected. 在这种情况下,将不会选择实体。 But if the user only had role 1, the entity would be selected. 但是,如果用户仅具有角色1,则将选择实体。 Of course, the SecureEntity may contain a bunch of other roles that the user does not have and are irrelevant. 当然,SecureEntity可能包含用户没有的,不相关的许多其他角色。

The sql code below works and does this: 'select the entity if the highest priority role permission that the user also has is Allow=true'. 下面的sql代码可以运行并执行以下操作:“如果用户还具有的最高优先级角色权限为Allow = true,则选择实体”。 So it basically filters RolePermission on the users own roles (IN clause), sorts by Priority, and takes the highest one if that is an Allow. 因此,它基本上是根据用户自己的角色(IN子句)过滤RolePermission,按优先级排序,如果允许则采用最高的权限。

Here is the Sql: 这是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)

There may be another way to write the above Sql but it does what I need. 可能有另一种方式编写上面的Sql,但是它满足了我的需要。 Ideally I would like to achieve this using NHibernate Linq or Criteria. 理想情况下,我想使用NHibernate Linq或Criteria实现。 I spent a few hours trying to get Linq to work and failed with various 'invalid operation' exceptions on the inner join to RolePermission. 我花了几个小时试图使Linq正常工作,但在与RolePermission的内部联接上出现各种“无效操作”异常而失败。 I don't have much experience with ICriteria or MultiCriteria and would be interested if anybody can help me. 我在ICriteria或MultiCriteria方面没有太多经验,如果有人可以帮助我,我会很感兴趣。

Note that the Fluent mapping for the objects is straightforward: 请注意,对象的Fluent映射非常简单:

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

and

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

Okay. 好的。 I couldn't get this to work using native NH Linq, although that doesn't mean that it is not possible. 我无法使用本机 NH Linq来实现此目的,尽管这并不意味着不可能。 But I looked through all the NH unit tests for Linq and couldn't find anything equivalent. 但是我仔细检查了Linq的所有NH单元测试,找不到任何等效的东西。

To get it working I created a database function called UserHasPermission that does everything in: 为了使其正常工作,我创建了一个名为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)

This works with any kind of secured entity. 这适用于任何类型的安全实体。 I then mapped that function as an NH Linq function by following the instructions in this page: http://wordpress.primordialcode.com/index.php/2010/10/01/nhibernate-customize-linq-provider-user-defined-sql-functions/ . 然后,我按照此页面中的说明将该函数映射为NH Linq函数: http : //wordpress.primordialcode.com/index.php/2010/10/01/nhibernate-customize-linq-provider-user-defined- sql-functions /

If you follow those instructions, you have to create a normal LinqToObjects extension in C# that has an identical signature to your database one. 如果遵循这些说明,则必须在C#中创建一个普通的LinqToObjects扩展,其扩展名与数据库的签名相同。 You can then do your NH Linq query like: 然后,您可以执行NH Linq查询,例如:

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

The only problem I found was that my original Sql function returned a bit, which I mapped to a NH Boolean type. 我发现的唯一问题是我原来的Sql函数返回了一点,并将其映射到NH布尔类型。 However this produced a really strange bit of sql that had several "Where ''True'' = ''True''" clauses that blew up in Sql Server. 但是,这产生了一个非常奇怪的sql语句,其中包含几个在SQL Server中炸毁的“ Where” True” =“ True””子句。 So I changed the result to an integer and everything worked okay. 所以我将结果更改为整数,一切正常。 A bit counter-intuitive, but... 有点违反直觉,但是...

Doing it this way allowed me to carry on transparently using Linq for all my queries, without affecting existing code, because it automatically prepended each query with the security check. 通过这种方式,我可以对所有查询透明地使用Linq进行操作,而不会影响现有代码,因为它会自动在每个查询之前进行安全检查。

Note that I looked in the Rhino Security source code and it uses a multiple criteria that is much too complex for me to understand with my limited NH knowledge. 请注意,我查看了Rhino Security源代码,它使用了多个标准,对于我有限的NH知识来说,这对于我来说太复杂了。 If I had done it using CreateCriteria, could I have combined it with Linq though? 如果我使用CreateCriteria完成此操作,是否可以将其与Linq结合使用?

  • The instructions in the above link do not make it clear that when you have created your own Dialect that registers your Sql function, you have to make sure you reference it in your NH configuration file (or code), otherwise you will get some kind of 'unknown type' exception. 上面链接中的说明并不清楚,当您创建自己的方言来注册Sql函数时,必须确保在NH配置文件(或代码)中引用它,否则您将获得某种“未知类型”异常。

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

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