6

I have the below two classes:

public class Project
{

    public virtual int ProjectId { get; set; }
    public virtual string ProjectName { get; set; }
    public virtual LegalEntity LegalEntity { get; set; }
}

and

public class LegalEntity
{
    public virtual int LegalEntId { get; set; }
    public virtual string Name { get; set; }
}

with mappings as:

<class name="Project" table="Project" dynamic-update="true">
  <id name="ProjectId">
    <generator class="native"/>
  </id>  

  <property name="ProjectName" />
  <many-to-one name="LegalEntity" column="LegalEntId" fetch="join" cascade="all-delete-orphan" />


</class>

and

<class name="LegalEntity" table="LegalEnt" dynamic-update="true">

  <id name="LegalEntId">

    <generator class="native"/>

  </id>



  <property name="Name" />    

</class>

In database, Project table has a FK to LegalEntity's PK column. One Project will have only one legal entity. Different projects can have same legal entity. So thats the reason I have gone for many-to-one. Not sure if this is correct though.

Insert and update is working fine. But if I update a legal entity id in a project and that legal entity becomes orphan, I want it to be deleted. But its not happening. Am I wrong in understanding delete-all-orphan? If yes, how can I achieve this behaviour?

Vikram
  • 608
  • 1
  • 7
  • 18

2 Answers2

10

The many-to-one cascade does not support all-delete-orphan, see:

<many-to-one
    ...
    cascade="all|none|save-update|delete"              (4)
    ...

Also, it would be almost impossible to handle this feature by NHibernate's session. Because it does not have to be clear, that the referenced many-to-one is really orphan. There should be some farther checks in DB... there could be other places referencing this table row...

Suggestion: do it in your code as a part of the DAO or Business Facade implementation. Check if there are really no dependencies, and then issue explicit Delete()

EXTEND: Here is a QueryOver syntax to get a list of all "orphan" LegalEntity

// subquery
var subquery = QueryOver.Of<Project>()
    .Select(x => x.LegalEntity.LegalEntId);

// just these legal entities, which are NOT used
var query = session.QueryOver<LegalEntity>()
    .WithSubquery
      .WhereProperty(y => y.LegalEntId)
      .NotIn(subquery)
    ;

// orphans
var list = query
    .List<LegalEntity>();
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Thanks for your reply. In SQL, I would have done the query: select * from LegalEnt where LegalEntId not in (select LegalEntId from Project) Whats will be the equivalent query for this in NH? – Vikram Jun 16 '14 at 12:22
  • Almost the same in NHibernate ;) Check http://nhforge.org/doc/nh/en/index.html#queryqueryover-simpleexpressions where you can quickly get idea how to use `QueryOver` ... or ask here ;) – Radim Köhler Jun 16 '14 at 12:24
  • Thanks Radim. Your posts are very helful. I can't get it right to use QueryOver. If you can help me with converting the above SQL to NH I would really appreciate. – Vikram Jun 16 '14 at 13:31
  • I will show you how... (maybe later today, but I will). – Radim Köhler Jun 16 '14 at 13:36
  • I extended my answer, think it should be what you could use to get a list of orphans... iterate it and delete them... also, maybe check this: DML - http://nhforge.org/doc/nh/en/index.html#batch-direct – Radim Köhler Jun 16 '14 at 16:12
0

Now all-delete-orphan and delete-orphan have been implemented for many-to-one as you can see in this commit from Nov 19, 2014.

Those were not supported when the OP asked the questions or when Radim Köhler wrote his answer, but I think future visitors will appretiate the update.

The documentation is also updated and now says:

cascade="all|none|save-update|delete|delete-orphan|all-delete-orphan"

But the documentation is confusing now, because it still has the following note:
The cascade attribute permits the following values: all, save-update, delete, none.
So I've created a defect to fix that last part of the documentation.

Community
  • 1
  • 1
Mariano Desanze
  • 7,847
  • 7
  • 46
  • 67