【问题标题】:Delete Cascade is not working with NHibernate删除级联不适用于 NHibernate
【发布时间】:2014-06-29 14:32:37
【问题描述】:

我有一个表 Communication,它引用了 PersonCompany。 在 PersonCompany 的映射中,我为此参考定义了 Cascade-Delete:

this.HasMany(x => x.Communications)
  .AsSet()
  .KeyColumn("PersonCompanyId")
  .Fetch.Select()
  .Inverse()
  .Cascade.Delete();

但是当我现在执行闲置的 HQL 查询时:

var sql = "delete from PersonCompany where Person.Id in (:idList) or Company.Id in (:idList)";

var query = NHibernateHelper.CurrentSession.CreateQuery(sql);
query.SetParameterList("idList", contactIdList);
query.SetTimeout(0);
query.ExecuteUpdate();

我总是得到这个 SqlException:

DELETE 语句与 REFERENCE 约束“FK_PersonCompany_Communication”冲突。冲突发生在数据库“proconact”、表“dbo.Communication”、列“PersonCompanyId”中。 声明已终止。

我认为,NHibernate 现在应该删除通信中引用的记录级联 - 不应该吗?

我希望有人可以帮助我,我做错了什么。

【问题讨论】:

    标签: c# nhibernate fluent-nhibernate cascade nhibernate-cascade


    【解决方案1】:

    您使用的语法实际上是

    的一部分

    这实际上是用来在数据库服务器上进行 BULK 操作的。它们使用 HQL 语法,但不覆盖级联(因为它们不在内存中执行,只是在 DB 端执行)

    这样,我们可以加载要删除的对象...并显式删除它们。这将触发级联:

    //var sql = "delete from PersonCompany where Person.Id in (:idList) or Company.Id in (:idList)";
    var sql = "from PersonCompany where Person.Id in (:idList) or Company.Id in (:idList)";
    var query = NHibernateHelper.CurrentSession.CreateQuery(sql);
    query.SetParameterList("idList", contactIdList);
    query.SetTimeout(0);
    //query.ExecuteUpdate();
    var list = query.List<PersonCompany >();
    foreach (var item in list)
    {
        session.Delete(item);
    }
    session.Flush();
    

    发生的事情是,每一项都被删除,并放在ISession。在Delete() 期间,所有级联均已正确执行

    【讨论】:

    • 据我了解,级联删除将与来自“BennoDual”的代码一起使用,如果它是由ON DELETE CASCADE 在数据库端设置的。这是正确的理解吗?
    • @A_J,我敢打赌你知道答案。但我想说的是,无论任何外部 SQL 工具处理程序(包括 ORM、NHibernate)如何,都将简单地执行应用 DB 端级联。我不会将此视为“如果设置了 DB...,code 将起作用”,因为在这种情况下,它超出了应用程序域,不在我们的控制范围内。我们的代码只是一个静默触发器。设置(以及魔法触发器) 迟早会导致长时间的、令人沮丧的搜索“为什么这些行消失了”。换句话说,我的经验会保护我比较隐藏的数据库设置和应用程序映射/代码。
    • 同意。但是你的回答让我很困惑。如果数据库端的约束可以处理级联,为什么他要加载所有实体只是为了删除它们?您是否建议这样做是为了缓存一致性?
    • @A_J DB 端的 trigger 与您的评论一起出现。没有问题,也没有我的回答。不知道那怎么会让您感到困惑...我(在我的回答中)仅使用 NHIBERNATE 级联...并且仅在您将内容加载到会话中时才在应用程序方面工作。希望现在更清楚一点
    【解决方案2】:

    方法是,

    IList<PersonCompany> _pCompanies = ....; <load the required person companies>
    foreach (var pc in _pCompanies)
    {
    _session.delete(pc);
    }
    

    因为当您使用批量更新时,内置约束在 Nhibernate 中不起作用。您可以尝试创建一个数据库级别的约束。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      相关资源
      最近更新 更多