nHibernate Cascade AllDeleteOrphan:为什么NH要单独删除每个集合项

本文关键字:删除 集合 单独 AllDeleteOrphan Cascade 为什么 NH nHibernate | 更新日期: 2023-09-27 18:07:01

当我清除这样的childcollection

table.Indizes.Clear();
session.Flush();

则NH为集合中的每个项生成一个delete SQL:

DELETE FROM x_inddef WHERE ind_name = 'IDX_ADRKONZ_CODE' AND tbl_name = ' address 'DELETE FROM x_inddef WHERE ind_name = 'IDX_ADRKUND_EXT' AND tbl_name = ' address '

为什么不生成这样的语句?

DELETE FROM x_inddef WHERE tbl_name = 'ADRESSE'

是我的映射有问题,还是这只是正常的行为?

使用流畅映射的简化代码:

public class Table
{
    public virtual string Name {get;set;
    public virtual IList<Index> Indizes { get; set; }
}
public class TableOverride : IAutoMappingOverride<Table>
{
    public void Override(AutoMapping<Table> mapping)
    {
        mapping.Table("x_tables");
        mapping.Id(x => x.Name, "tbl_name");
        mapping.HasMany(x => x.Indizes).KeyColumn("tbl_name").Inverse().Cascade.AllDeleteOrphan();
    }
}
public class Index
{
    public virtual string Name { get; set; }
    public virtual Table Table { get; set; }
    public override bool Equals(object obj)
    {
        //...
    }
    public override int GetHashCode()
    {
        //...
    }
}
public class IndexOverride : IAutoMappingOverride<Index>
{
    public void Override(AutoMapping<Index> mapping)
    {
        mapping.Table("x_inddef");
        mapping.CompositeId().
            KeyProperty(x => x.Name, "ind_name").
            KeyReference(x => x.Table, "tbl_name");
    }
}

nHibernate Cascade AllDeleteOrphan:为什么NH要单独删除每个集合项

你应该启用nhibernate的批量更新选项

首先将NHibernate配置中的adonet.batch_size属性设置为value,大于0。

然后用.BatchSize(xxx)标记每个hasMany集合

mapping.HasMany(x => x.Indizes)
   .BatchSize(25)
   .KeyColumn("tbl_name")
   .Inverse()
   .Cascade.AllDeleteOrphan();

我想这应该有帮助

一次性删除不适用于逆=true。分配一个包含0个元素的索引集合的新实例并取消对旧实例的引用会引发一个异常,因为Nhibernate期望管理该集合。看来唯一的出路就是使用hql。

查看文档中的19.5.4节- http://www.nhforge.org/doc/nh/en/index.html

All-delete-orphan表示如果删除父元素,则子集合将被删除。
意思是-如果你删除了一个Table对象,那么DELETE FROM x_inddef WHERE tbl_name =...将被释放。
调用Clear()只是删除集合中所有对象的简写,但是Table对象本身保持不变。

另一个可能的解决方案是使用HQL:

session.CreateQuery("DELETE Index i WHERE i.Table.Name = :tblName")
    .SetString( "tblName", "MyTable" )
    .ExecuteUpdate();