14

我在一个系统中有一个场景,我试图尽可能地简化它。我们有一个(让我们称之为)人工制品表,人工制品可以被任意数量的安全角色访问,安全角色可以访问任意数量的人工制品。因此,我们在数据库中有 3 个表 - 一个描述人工制品,一张描述角色,以及一个将人工制品 ID 链接到角色 ID 的多对多关联表。

在领域方面,我们有两个类——一个用于角色,一个用于人工制品。artefact 类有一个 IList 属性,它返回可以访问它的角色列表。(但是,角色不提供获取可以访问的人工制品的属性)。

因此,人工制品的休眠映射包含以下内容;

<bag name="AccessRoles" table="ArtefactAccess" order-by="RoleID" 
    lazy="true" access="field.camelcase-underscore" optimistic-lock="false">
    <key column="ArtefactID"/>
    <many-to-many class="Role" column="RoleID"/>
</bag>

这一切都很好,如果我删除了一个人工制品,关联表将被适当地清理,并且删除的人工制品和角色之间的所有引用都被删除(尽管角色没有被正确删除——因为我们不希望删除孤儿)。

问题是 - 如何删除一个角色并让它自动清除关联表。如果我目前尝试删除一个角色,我会得到一个引用约束,因为该角色的关联表中仍有条目。成功删除角色的唯一方法是查询链接到该角色的所有人工制品,从人工制品的角色集合中删除该角色,更新人工制品,然后删除该角色 - 不是很有效或很好,尤其是在联合国 -简化的系统,角色可以与任意数量的其他表/对象相关联。

我需要能够向 NHibernate 提示我希望在删除角色时清除此关联表 - 这可能吗,如果可以的话 - 我该怎么做?

谢谢你的帮助。

4

5 回答 5

8

由于我一直在寻找这个答案并在谷歌上找到了这个帖子(没有答案),我想我会发布我的解决方案。带有三个表:Role、RolesToAccess(ManyToMany)、Access。

创建以下映射: 访问:

<bag name="Roles" table="RolesToAccess" cascade="none" lazy="false">
      <key column="AccessId" />
      <many-to-many column="AccessId" class="Domain.Compound,Domain" />
    </bag>

<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false">
      <key column="AccessId" on-delete="cascade" />
      <one-to-many class="Domain.RolesToAccess,Domain" />
    </bag>

角色:

<bag name="Accesses" table="RolesToAccess" cascade="none" lazy="false">
      <key column="RoleId" />
      <many-to-many column="RoleId" class="Domain.Compound,Domain" />
    </bag>

<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false">
      <key column="RoleId" on-delete="cascade" />
      <one-to-many class="Domain.RolesToAccess,Domain" />
    </bag>

如上所述,您可以使 RolesToAccess 属性受到保护,这样它们就不会污染您的模型。

于 2009-01-02T15:43:20.583 回答
1

你在这里说什么:

成功删除角色的唯一方法是查询链接到该角色的所有人工制品,从人工制品的角色集合中删除该角色,更新人工制品,然后删除该角色 - 不是很有效或很好,尤其是在联合国 -简化的系统,角色可以与任意数量的其他表/对象相关联。

没有必要。假设您不想映射关联表(使其成为域对象),您仍然可以用最少的代码在两端执行删除。

假设有 3 个表:Role、Artifact 和 ArtifactAccess(链接表)。在您的映射中,您只有角色和工件的域对象。两者都有一个用于多对多关联的包。

角色:

    <bag name="Artifacts" table="[ArtifactAccess]" schema="[Dbo]" lazy="true"
        inverse="false" cascade="none" generic="true">
        <key column="[ArtifactID]"/>

        <many-to-many column="[RoleID]" class="Role" />
    </bag>

神器:

    <bag name="Roles" table="[ArtifactAccess]" schema="[Dbo]" lazy="true"
        inverse="false" cascade="none" generic="true">
        <key column="[RoleID]"/>

        <many-to-many column="[ArtifactID]" class="Role" />
    </bag>

如您所见,两端都指定了 inverse=false。NHibernate 文档建议您选择关联的一端作为“反向”端,但没有什么能阻止您将两者都用作“控制端”。在执行更新或插入时,这可以从两个方向顺利进行。在执行任一端的删除时,您会收到 FK 违规错误,因为关联表未更新,true。但是您可以通过在执行删除之前将集合清除到另一端来解决这个问题,这比您所做的要简单得多,如果有使用 'this,则在关联的“另一端”中查找' 结尾。如果这有点令人困惑,这里有一个代码示例。如果您只有一个控制端,对于您的复杂删除,您需要执行以下操作:

foreach(var artifact in role.Artifacts)
    foreach(var role in artifact.Roles)
        if(role == roleToDelete)
            artifact.Roles.Remove(role)
    artifact.Save();
roleToDelete.Delete();

删除角色时我所做的类似于

roleToDelete.Artifacts.Clear(); //removes the association record
roleToDelete.Delete(); // removes the artifact record

这是一行额外的代码,但这样您就不需要决定关联的哪一端是反向端。您也不需要映射关联表来进行完全控制。

于 2010-12-12T13:41:45.160 回答
0

您可以为关联表进行映射,然后对该表调用 delete,其中 Role_id 是您要删除的值,然后执行角色本身的删除。这样做应该相当简单。

于 2008-10-17T17:30:00.403 回答
0

虽然我相信 NHibernate 必须提供一种方法来做到这一点,而无需在角色 C# 类中包含集合,但您始终可以在 SQL 中设置此行为。为数据库中的 FK 选择级联删除,它应该是自动的,只需注意 NHib 的缓存。

但我强烈建议您将此作为最后的资源。

于 2008-10-17T20:35:31.810 回答
0

您需要创建从 Role 到Artifact.

您可以使其延迟加载,并将其映射到受保护的虚拟成员,这样它就不会真正被访问,但您需要该映射以便 NHibernate 知道它必须从ArtefactAccess表中删除角色

于 2008-10-17T23:08:30.063 回答