doerig
doerig

Reputation: 1857

nHibernate Cascade AllDeleteOrphan: Why is NH deleting each collection item individually

When I'm clearing a childcollection like this

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

then NH generates a delete SQL for each item which was in the collection:

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'

...

Why isn't it generating a statement like this?

DELETE FROM x_inddef WHERE tbl_name = 'ADRESSE'

Is something wrong with my mappings, or is this just the normal behaviour?

Simplified Code with the fluent Mapping:

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

Upvotes: 0

Views: 1733

Answers (4)

doerig
doerig

Reputation: 1857

Another possible solution is to use HQL:

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

Upvotes: 0

hazzik
hazzik

Reputation: 13344

You should enable batch updates option with nhibernate

First of all set adonet.batch_size property in your NHibernate configuration to value, greater then zero.

And then mark each hasMany collection with .BatchSize(xxx)

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

I guess this should help

Upvotes: 3

Sriram
Sriram

Reputation: 838

One-shot deletes do not work with inverse=true. Allocating a new instance of the index collection with 0 elements and dereferencing the old one throws an exception as Nhibernate expects to manage the collection. It seems the only way out is to use hql.

Check section 19.5.4 in the documentation - http://www.nhforge.org/doc/nh/en/index.html

Upvotes: 1

J. Ed
J. Ed

Reputation: 6742

All-delete-orphan means that your child collection would be deleted if you delete the parent element.
meaning- if you delete a Table object, than DELETE FROM x_inddef WHERE tbl_name =... would be issued.
calling Clear() is just a shorthand for deleting all the objects in a collection, but the Table object itself remains intact.

Upvotes: 0

Related Questions