【问题标题】:Many-to-one cascade delete NHibernate results in RESTRICT (MySQL 5)多对一级联删除 NHibernate 导致 RESTRICT (MySQL 5)
【发布时间】:2013-08-05 18:08:41
【问题描述】:

我有一个简单的category 课程。每个category 可以有零个或多个category 类型的子代。因此,我选择注册category 的父级,它可以为null 或另一个category 的id。当 category 被删除时,它的所有子项(category 类型)也必须被删除。

NHibernate创建表的schema时,外键存在,但On Delete:设置为RESTRICT。 注意:当我手动将 On Delete: 更改为 CASCADE 时,一切都按预期工作。

我了解到这是将孩子与父母联系起来的错误方法。我不明白为什么。因此,它有效。但是 NHibernate 并没有按照我的意愿配置 On Delete

我读过关于反向收藏品和包袋的信息,并使用单独的表格。但我对我的方法应该是什么感到困惑。

如何使用这个category 类实现delete cascade,为什么?

我的映射如下所示:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="BackEnd"
                   namespace="BackEnd.Models">
  <class name="Category">
    <id name="Id">
      <generator class="native"/>
    </id>
    <property name="Name" />
    <many-to-one class="Category" name="Parent" cascade="delete"/>
    <property name="Description" />
  </class>
</hibernate-mapping>

【问题讨论】:

  • 孩子也可以有孩子,也可以有孩子等等?
  • 是的,他们可以。每个类别只能有 1 个父级(数据库中的 ParentId 列)。但是每个父母可以有更多的子类别。所以可能有多个级别。
  • 我现在正在研究在 IList 中映射子类别,而不是在加载类别时使用急切/延迟加载来加载父类别。网上所有的例子都有两张表。但是为什么我需要两张桌子呢?

标签: nhibernate cascade many-to-one cascading-deletes


【解决方案1】:

这就是如何在同一个表中映射父子关系,列出所有子对象到您的对象,并在删除父对象时删除所有子对象。

我终于通过反复试验得到了这个。我尝试了 15 次。

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                       assembly="BackEnd"
                       namespace="BackEnd.Models">
      <class name="Category">
        <id name="Id">
          <generator class="native"/>
        </id>
        <property name="Name" />
        <property name="ParentId" />
        <bag name="Children" table="Category" inverse="true" cascade="all-delete-orphan">
          <key column="ParentId" on-delete="cascade"/>
          <one-to-many class="Category"/>
        </bag>
        <property name="Description" />
      </class>
    </hibernate-mapping>

这是我使用的类的代码。

/// <summary>
/// The ModelBase takes care of the CRUD (Create, Read, Update, Delete) functionalities for each derived class.
/// public functions here must be virtual, read this: http://thatextramile.be/blog/2009/03/must-everything-be-virtual-with-nhibernate/
/// This is an abstract class as it has no purpose on its own.
/// </summary>
public abstract class ModelBase<T>
{

    /// <summary>
    /// The id by which this transient object is related to a persistent object in database.
    /// </summary>
    public virtual ulong Id { get; set; }


    /// <summary>
    /// Many objects, like categories, issues, etc, can have a parent of the same type
    /// </summary>
    public virtual ulong ParentId { get; set; }

    /// <summary>
    /// The childeren of this object, if any
    /// </summary>
    public virtual IList<T> Children
    {
        get;
        set;
    }

    /// <summary>
    /// Constructor only available for derived classes.
    /// </summary>
    protected ModelBase()
    {
    }

    /// <summary>
    /// Creates or updates this object in database.
    /// </summary>
    public virtual void CreateOrUpdate()
    {
        using(ISession Session = Gate.SessionFactory.OpenSession())
        {
            Session.SaveOrUpdate(((T)((Object)this)));
            Session.Flush();
            Session.Close();
        }
    }

    /// <summary>
    /// Deletes this object from database
    /// </summary>
    public virtual void Delete()
    {
        using (ISession Session = Gate.SessionFactory.OpenSession())
        {
            Session.Delete(((T)((Object)this))); //Needs to be casted as the type of the top most class, or it will fail to get its properties.
            Session.Flush();
            Session.Close();
        }
    }

    /// <summary>
    /// Loads a persistent object (from database) in to a transienst object (variable).
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Id">The Id of the object by which it is known in database.</param>
    /// <returns>A strong typed object.</returns>
    public static T Load(ulong Id)
    {
        /* TODO: Lazy loading only possible when sessinos remains open.
         * Solve this by adding some kind of OnDispose event that automatically closes the connection when the object is disposed.
         */
        //using (ISession Session = Gate.SessionFactory.OpenSession())
        //{
        //    ModelObject = Session.Load<T>(Id);
        //    Session.Close();
        //}
        ISession Session = Gate.SessionFactory.OpenSession();
        return Session.Load<T>(Id);
    }
}

最后是从基类派生的类别类

/// <summary>
/// A part can be categorized, under one or more, categories.
/// Each category is an instance of this class.
/// </summary>
public class Category : ModelBase<Category>
{
    /// <summary>
    /// The name of the category that is displayed to the user.
    /// </summary>
    public virtual String Name { get; set; }    

    /// <summary>
    /// A description of what this category is about.
    /// </summary>
    public virtual String Description { get; set; }

    /// <summary>
    /// The constructor creates a new category object.
    /// </summary>
    public Category()
    {
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多