2

我有两个类的两个 Nhibernate 映射,类别和产品。我的 Category 类有两个属性是集合。Children 属性是一个 Category 类型的集合,它代表子类别(代表一个类别菜单,典型的父子场景)。Category 类的第二个属性是 Products 集合,它代表一个类别下的所有产品。

我想要实现的是当我删除一个类别时,我希望删除该类别而不是产品。所以我希望产品成为孤儿。即在Product 表中将其外键(CategoryId) 设置为null。我不想仅仅因为我删除了一个类别就删除了一个产品。我希望以后能够重新分配到另一个类别。我的代表上述场景的映射如下。

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="naakud.domain" namespace="naakud.domain">
  <class name="Category">
    <id name="Id">
      <generator class="hilo" />
    </id>
    <version name="Version"/>
    <property name="Name" not-null="true" unique="true" />
    <set name="Products"
         cascade="save-update"
         inverse="true"
         access="field.camelcase-underscore">
      <key column="CategoryId" foreign-key="fk_Category_Product" />
      <one-to-many class="Product" />
    </set>
    <many-to-one name="Parent" class="Category" column="ParentId" />
    <set name="Children"
         collection-type="naakud.domain.Mappings.Collections.TreeCategoriesCollectionType, naakud.domain"
         cascade="all-delete-orphan"
         inverse="true"
         access="field.camelcase-underscore">
      <key column="ParentId" foreign-key="fk_Category_ParentCategory" />
      <one-to-many class="Category"/>
    </set>
  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="naakud.domain" namespace="naakud.domain">
  <class name="Product">
    <id name="Id">
      <generator class="hilo" />
    </id>
    <version name="Version" />
    <property name="Name" not-null="true" unique="true" />
    <property name="Description" not-null="true" />
    <property name="UnitPrice" not-null="true" type="Currency" />
    <many-to-one name="Category" column="CategoryId" />
  </class>
</hibernate-mapping>

使用此映射,当我删除具有与之关联的产品的类别时,我会收到以下约束错误。

DELETE 语句与 REFERENCE 约束“fk_Category_Product”冲突。冲突发生在数据库“naakud”、表“dbo.Product”、列“CategoryId”中。该语句已终止。

但是,当我在 Category 映射中删除 Products 集合上的 inverse=true 属性时,它可以正常工作。我在 products 表中的 CategoryId 外键设置为 null,从而取消了产品与类别的关联。这就是我想要的。

我已经阅读了有关 inverse 属性的信息,并且我理解它表示关系的拥有方,并且更新/插入/删除以不同的顺序完成,这就是我认为它解决了我的问题的原因。所以我的问题是,我是否以正确的方式解决了我的问题?这对性能有何影响?(我怀疑不多)。是否有一个单向关系而没有多向一侧并将反向属性设置为 true 以获得更好的性能?还是我要疯了,完全错过了重点?

4

2 回答 2

1

解决删除问题的另一种方法是在刷新之前将所有相关实体上的多对一属性设置为 null。

我至少可以想到两种方法:

  • 在调用 的同一方法中session.Delete(category),执行以下操作:

    foreach (var product in category.Products)
        product.Category = null;
    
  • 使用 HQL:

    session.CreateQuery(
           "update Product set Category = null where Category = :category")
           .SetParameter("category", category)
           .ExecuteUpdate();
    

更新

这是使用事件侦听器的概念验证实现。

于 2011-03-19T22:12:54.250 回答
0

我假设您阅读了NHibernate 中的逆属性

正如错误消息所说,您的 DELETE 会与外键约束产生冲突,这意味着只要有引用该特定类别的产品,数据库就无法删除该类别。

您可以做的(如果您可以更改数据库模式)将“ON DELETE SET NULL”应用于您的外键约束。这样,在执行 DELETE 时,数据库会自动将 Product 表中的所有引用设置为 NULL。

如果您无法修改外键,那么您别无选择,只能删除 inverse 属性。这样做会导致 NHibernate 首先将 Product.Category 引用设置为 NULL,然后删除 Category。

如果您经常需要 Product.Category,那么您不应该摆脱 Product 中的多对一属性。

关于性能,这取决于您插入产品的频率。每次插入都会导致额外的更新来设置外键。不过,这应该不是问题。

于 2011-03-17T23:19:23.640 回答