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

时间:2011-08-31 07:17:56

标签: c# nhibernate fluent-nhibernate

当我清理像这样的儿童集合时

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

然后NH为集合中的每个项目生成一个删除SQL:

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

...

为什么不生成这样的声明?

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");
    }
}

4 个答案:

答案 0 :(得分:3)

您应该使用nhibernate

启用批量更新选项

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

然后使用.BatchSize(xxx)

标记每个hasMany集合
mapping.HasMany(x => x.Indizes)
   .BatchSize(25)
   .KeyColumn("tbl_name")
   .Inverse()
   .Cascade.AllDeleteOrphan();

我想这应该有帮助

答案 1 :(得分:1)

一次性删除不适用于inverse = true。使用0个元素分配索引集合的新实例并解除引用旧元素会抛出异常,因为Nhibernate期望管理集合。似乎唯一的出路就是使用hql。

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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