【问题标题】:Many-to-many and HQL batch delete多对多和HQL批量删除
【发布时间】:2011-02-26 20:53:43
【问题描述】:

我有两个定义了多对多关系的实体。

<set name="TreasuryCodes" table="ServiceProviderAccountTreasuryCode" lazy="true" cascade="all">
  <key column="ServiceProviderAccountId" />
  <many-to-many column="TreasuryCodeId" class="TreasuryCode" />
</set>

<set name="ServiceProviderAccounts" table="ServiceProviderAccountTreasuryCode" lazy="true" inverse="true" cascade="all">
  <key column="TreasuryCodeId" />
  <many-to-many column="ServiceProviderAccountId" class="ServiceProviderAccount" />
</set>

现在我想通过 ServiceProviderId 删除所有 ServiceProviderAccounts。我写了这段代码:

    public void DeleteAllAccount(int serviceProviderId)
    {
        const string query = "delete ServiceProviderAccount spa where spa.ServiceProvider.Id = :serviceProviderId";
        repository.Session.CreateQuery(query)
            .SetInt32("serviceProviderId", serviceProviderId)
            .ExecuteUpdate();
        repository.Session.Flush();
    }

我收到了这个异常:

Test method Test.ServiceRepositoryTest.DeleteAllAccountTest threw exception: 
NHibernate.Exceptions.GenericADOException: could not execute update query[SQL: delete from ServiceProviderAccount where ServiceProviderId=?] ---> System.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FKBC88A84CB684BF79". The conflict occurred in database "Test", table "dbo.ServiceProviderAccountTreasuryCode", column 'ServiceProviderAccountId'.
The statement has been terminated.

我很困惑,因为我在实体上定义了级联,不应该从 ServiceProviderAccountTreasuryCode 中删除行?

更新


好的,看起来 ExecuteUpdate 不是在寻找 NHibernate 级联,可能是因为它在删除实体之前没有加载它?无论如何,还有其他方法可以从 ServiceProviderAccountTreasuryCode 表中删除,然后通过 HQL 从 ServiceProviderAccounts 中删除吗?我知道我可以在数据库上使用级联,但我想避免这种情况。我想要的是通过 HQl 从多对多关联表中删除行。是否可以?还是我应该使用纯 SQL?

【问题讨论】:

    标签: nhibernate hql nhibernate-mapping


    【解决方案1】:

    看起来你有一个参照完整性问题,即一个外键关系,你正在删除的 id 在其他地方被引用,而该表最终不会引用任何内容。如果这是您想要做的,那么您可以运行 Truncate 命令,但我不确定您为什么要这样做..

    我建议您进行正常删除,即使用 nhibernate 会话和 Linq,如下所示:

     foreach(var sessionProvider in Session.Linq<ServiceProviderAccount >().Where(x=>x.ServiceProvider.Id==servinceProviderId))
           Session.Delete(sessionProvider);
    

    现在请注意,这根本不是一个糟糕的删除方法,因为它们不会立即针对 dB 触发,并且在您的事务提交之前是 Session 的一部分,如果您的映射已定义,这应该可以处理您的引用完整性问题没错。

    希望这有效..

    【讨论】:

    • 是的,我做了一些研究,看起来你的解决方案是唯一的。谢谢
    【解决方案2】:

    看起来它不服从级联。更新/删除的 HQL 批处理操作相对较新,或多或少直接转换为 SQL。我相信您也必须跟踪相关表格。

    如果您只删除单个实体,那么批量删除对您没有多大好处。为了让 NHibernate 真正考虑级联,它必须加载实际的实体,而您的示例中没有。

    我问了一个类似的问题,我得到的答案可能会让你感兴趣

    Remove entity in NHibernate only by primary key

    【讨论】:

    • 我不会删除单个实体。我要一口气删除几个。我想要的是生成类似于 DELETE FROM [table] WHERE some_filed = @someparam 的东西
    猜你喜欢
    • 2010-11-15
    • 1970-01-01
    • 2012-10-28
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    相关资源
    最近更新 更多