如何在NHibernate(而不是FluentNHibernate)中映射此类?

如何在NHibernate(而不是FluentNHibernate)中映射此类?,nhibernate,nhibernate-mapping,Nhibernate,Nhibernate Mapping,假设我有这样一个数据库: 此设置用于授予角色菜单权限 请注意,用户-表与权限-表没有直接关系。 那么我应该如何将这个类映射到数据库表呢 class User { public int ID { get; set; } public string Name { get; set; } public string Username { get; set; } public string Password { get; set;

假设我有这样一个数据库:

此设置用于授予角色菜单权限

请注意,
用户
-表与
权限
-表没有直接关系。

那么我应该如何将这个类映射到数据库表呢

class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public bool? IsActive { get; set; }

        public IList<Role> RoleItems { get; set; }
        public IList<Permission> PermissionItems { get; set; }
        public IList<string> MenuItemKeys { get; set; }
    }
类用户
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共字符串用户名{get;set;}
公共字符串密码{get;set;}
公共bool?IsActive{get;set;}
公共IList角色项{get;set;}
公共IList权限项{get;set;}
公共IList MenuItemKeys{get;set;}
}
这就是说,

(1) 每个用户都有一些
角色

(2) 每个用户都有一些
权限
s(取决于to
角色
s)

(3) 每个用户都有一些允许的
MenuItemKey
s(根据
Permission
s)

我的
User.hbm.xml
应该是什么样子?

这里有一个链接: 下面是另一个有用的链接:

编辑

经过一整晚的研究,我得出了以下结论:

  • 考虑到,你想做的是没有好处的 不要使用外来关联映射。
    真正多对多关联的好用例很少。大多数情况下,您需要存储在“链接表”中的其他信息。在这种情况下,最好对中间链接类使用两个一对多关联。事实上,我们认为大多数关联都是一对多和多对一的,在使用任何其他关联样式时都应该小心,问问自己这是否真的必要

  • 作为一种编程哲学,我更喜欢保持它的简单性,而不是必须编写聪明的代码,即使是我在一段时间后也无法理解我所写的东西
  • 另外,我甚至考虑使用关联映射的子查询元素,如果我能找到一种参数化它的方法(如果可行的话),该元素会起作用,但它似乎不允许我用用户实例的Id属性值参数化查询
  • 在一个精心设计的OO模型中,一个孩子意识到他父母的财产是很好的,但是一个父母访问一个孩子的财产却没有感觉到设计的味道
  • 考虑到上下文公开了用户直接访问权限或MenuItemKey值的好处,我可以理解,我建议以下解决方案:

    • 自己创建一个用户定义的数据视图,该视图将保存与通过用户作为成员的角色获得的MenuItemKey权限属性相关的值,如下所示:
  • 将视图UDVuser任务创建为
    选择UR.UserID,P.ID作为N'ID',P.MenuItemKey
    来自用户U
    UR.UserID=U.ID上的内部连接UsersRoles UR
    R.ID=UR.RoleID上的内部联接角色R
    P.RoleID=R.ID上的内部联接权限P

    然后,根据User.hbm.xml文件映射它:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
      <class name="User" table="Users">
        <id name="Id" column="ID">
          <generator class="identity"/>
        </id>
        <property name="Name" length="100"/>
        <property name="UserName" length="10" not-null="true"/>
        <property name="Password" length="10" not-null="true"/>
        <property name="IsActive" not-null="true"/>
    
        <list name="Roles" table="UsersRoles" access="private-property" lazy="true">
          <key column="UserID" foreign-key="FK_UR_U"/>
          <list-index column="UserID"/>
          <many-to-many class="Role" column="RoleID" />
        </list>
    
        <!-- Here mapping Permissions granted to User. -->
        <list name="Permissions" table="udvUsersPermissions" lazy="true">
          <key column="UserID"/>
          <list-index column="MenuItemKey"/>
          <many-to-many column="ID" class="Permission"/>
        </list>
    
      </class>
    </hibernate-mapping>
    
    
    
    在这里,我会让你知道subselect解决方案,以防它以我没有预料到的方式工作

    <list name="Permissions" lazy="true">
      <subselect> <!-- see section 7.6, Chapter 7 - Association mappings -->
        select U.ID, P.ID, P.MenuItemKey
        from Users U
        inner join UsersRoles UR ON UR.UserID = U.ID
        inner join Roles R ON R.ID = UR.RoleID
        inner join Permissions P ON P.RoleID = R.ID
        group by U.ID, P.ID, P.MenuItemKey
        order by P.MenuItemKey
      </subselect>
      <key column="U.ID"/>
      <list-index column="P.MenuItemKey"/>
      <many-to-many class="Permission" column="P.ID"/>
    </list>
    
    
    选择U.ID、P.ID、P.MenuItemKey
    来自用户U
    UR.UserID=U.ID上的内部联接UsersRoles UR
    R.ID=UR.RoleID上的内部联接角色R
    P.RoleID=R.ID上的内部联接权限P
    按U.ID、P.ID、P.MenuItemKey分组
    按P.MenuItemKey订购
    

    现在,我希望我带来了足够的细节,这样可以帮助你实现你想做的事情,或者让你走上正轨

    角色和权限在应用程序中可能会被大量访问。它们很可能位于二级缓存中,这意味着我们可以有效地迭代User.RoleItems和Role.Permissions

    这样做的优点是,在迭代这些集合时,我们通常可以不执行查询

    您可以按如下方式映射这些类

    属性User.PermissionItems和User.MenuItemKeys是从持久实体派生的,因此不会出现在映射中

    <class name="User" table="user">
      <id name="ID">
        <generator class="native"/>
      </id>
      <property name="Name"/> 
      <property name="Username"/>
      <property name="Password"/>
      <property name="IsActive"/>
    
      <bag name="RoleItems" table="userrole" lazy="true">
        <key column="userid" />
        <many-to-many class="Role" column="roleid"/>
      </bag>
    </class>
    
    <class name="Role" table="role">
      <id name="ID">
        <generator class="native"/>
      </id>
      <property name="RoleName"/>
      <property name="IsActive"/>
    
      <bag name="Permissions" table="permission">
        <key column="roleid" />
        <one-to-many class="Permission"/>
      </bag>
    </class>
    
    <class name="Permission" table="permission">
      <id name="ID">
        <generator class="native"/>
      </id>
      <property name="MenuItemKey"/>
    </class>
    
    
    
    我会将用户上的另外两个列表制作成派生枚举。如果它们是列表,则没有明确的方法插入其中,因为您无法知道该值应用于哪个角色。此外,角色不属于用户

    更新:现在使用Diego对这些属性的改进版本

    class User
    {
        public virtual IEnumerable<Permission> PermissionItems
        {
            get {
                return RoleItems.SelectMany(role => role.PermissionItems);
            }
        }
    
        public virtual IEnumerable<string> MenuItemKeys
        {
            get {
                return RoleItems.SelectMany(role => role.PermissionItems,
                            (role, permission) => permission.MenuItemKey);
            }
        }
    }
    
    类用户
    {
    公共虚拟IEnumerable权限项
    {
    得到{
    返回RoleItems.SelectMany(角色=>role.PermissionItems);
    }
    }
    公共虚拟IEnumerable MenuItemKey
    {
    得到{
    返回RoleItems.SelectMany(角色=>role.PermissionItems,
    (角色,权限)=>permission.MenuItemKey);
    }
    }
    }
    
    拉克兰发布的地图是最好的选择。可以使用对每个集合执行所有联接的查询,但这会使它们仅用于实际目的

    但是,有一种更容易实现属性代码的方法,可以帮助您决定:

    public IEnumerable<Permission> PermissionItems
    {
        get
        {
            return RoleItems.SelectMany(role => role.PermissionItems);
        }
    }
    
    public IEnumerable<string> MenuItemKeys
    {
        get
        {
            return RoleItems.SelectMany(role => role.PermissionItems,
                                       (role, permission) => permission.MenuItemKey);
        }
    }
    
    public IEnumerable权限项
    {
    得到
    {
    返回RoleItems.SelectMany(角色=>role.PermissionItems);
    }
    }
    公共IEnumerable MenuItemKey
    {
    得到
    {
    返回RoleItems.SelectMany(角色=>role.PermissionItems,
    (角色,权限)=>permission.MenuItemKey);
    }
    }
    
    为什么不将用户映射到角色,将权限映射到角色。然后使用角色获取权限?一个简单的linq查询:var permissions=user.RoleItems.SelectMany(x=>x.PermissionItems);(或您的计算机上的方法)