Skip to content

Commit 3e4cf2a

Browse files
author
mickfold
committed
For NH-1262: Ported cascade delete orphans functionality for one-to-one mappings from Hibernate to NHibernate.
Mappings can be made in XML or MappingByCode. The following scenarios are supported: 1) Bidirectional primary key based one-to-one. 2) Unidirectional shared primary key based one-to-one 3) Bidirectional foreign key based one-to-one with orphan delete declared on the non-constrained (<one-to-one/>) side. 4) Bidirectional foreign key based one-to-one with orphan delete declared on the constrained (<many-to-one unique="true"/>) side. 5) Unidirectional foreign key based one-to-one with orphan delete declared on the constrained (<many-to-one unique="true"/>) side. 6) Unidirectional foreign key based one-to-one with orphan delete declared on the constrained side (<many-to-one unique="true"/>) where the foreign key is composite (multiple columns).
1 parent fac75a2 commit 3e4cf2a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2016
-40
lines changed

doc/reference/modules/basic_mapping.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,7 @@
16281628
name="PropertyName"
16291629
column="column_name"
16301630
class="ClassName"
1631-
cascade="all|none|save-update|delete"
1631+
cascade="all|none|save-update|delete|delete-orphan|all-delete-orphan"
16321632
fetch="join|select"
16331633
update="true|false"
16341634
insert="true|false"
@@ -1788,7 +1788,7 @@
17881788
<programlisting><![CDATA[<one-to-one
17891789
name="PropertyName"
17901790
class="ClassName"
1791-
cascade="all|none|save-update|delete"
1791+
cascade="all|none|save-update|delete|delete-orphan|all-delete-orphan"
17921792
constrained="true|false"
17931793
fetch="join|select"
17941794
property-ref="PropertyNameFromAssociatedClass"

doc/reference/modules/manipulating_data.xml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,14 +1043,15 @@ finally
10431043
</itemizedlist>
10441044

10451045
<para>
1046-
Mapping an association (many-to-one, or collection) with <literal>cascade="all"</literal>
1046+
Mapping an association (many-to-one, one-to-one or collection) with <literal>cascade="all"</literal>
10471047
marks the association as a <emphasis>parent/child</emphasis> style relationship where
10481048
save/update/deletion of the parent results in save/update/deletion of the child(ren).
10491049
Futhermore, a mere reference to a child from a persistent parent will result in save / update
10501050
of the child. The metaphor is incomplete, however. A child which becomes unreferenced by its
1051-
parent is <emphasis>not</emphasis> automatically deleted, except in the case of a
1052-
<literal>&lt;one-to-many&gt;</literal> association mapped with
1053-
<literal>cascade="all-delete-orphan"</literal>. The precise semantics of cascading operations
1051+
parent is <emphasis>not</emphasis> automatically deleted, except in the cases of
1052+
<literal>&lt;one-to-many&gt;</literal> and <literal>&lt;one-to-one&gt;</literal> associations
1053+
that have been mapped with <literal>cascade="all-delete-orphan"</literal> or
1054+
<literal>cascade="delete-orphan"</literal>. The precise semantics of cascading operations
10541055
are as follows:
10551056
</para>
10561057

@@ -1081,8 +1082,8 @@ finally
10811082
<para>
10821083
If a transient child is dereferenced by a persistent parent, <emphasis>nothing
10831084
special happens</emphasis> (the application should explicitly delete the child if
1084-
necessary) unless <literal>cascade="all-delete-orphan"</literal>, in which case the
1085-
"orphaned" child is deleted.
1085+
necessary) unless <literal>cascade="all-delete-orphan"</literal> or
1086+
<literal>cascade="delete-orphan"</literal>, in which case the "orphaned" child is deleted.
10861087
</para>
10871088
</listitem>
10881089
</itemizedlist>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using NUnit.Framework;
2+
using System.Collections;
3+
4+
namespace NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Bidirectional
5+
{
6+
[TestFixture]
7+
public class DeleteOneToOneOrphansTest : TestCase
8+
{
9+
protected override string MappingsAssembly
10+
{
11+
get { return "NHibernate.Test"; }
12+
}
13+
14+
protected override IList Mappings
15+
{
16+
get { return new string[] { "Cascade.OneToOneCascadeDelete.Hbm.Fk.Bidirectional.Mappings.hbm.xml" }; }
17+
}
18+
19+
protected override void OnSetUp()
20+
{
21+
base.OnSetUp();
22+
using (var s = OpenSession())
23+
using (var t = s.BeginTransaction())
24+
{
25+
var emp = new Employee();
26+
emp.Info = new EmployeeInfo(emp);
27+
28+
s.Save(emp);
29+
t.Commit();
30+
}
31+
}
32+
33+
protected override void OnTearDown()
34+
{
35+
base.OnTearDown();
36+
37+
using (var session = OpenSession())
38+
using (var tx = session.BeginTransaction())
39+
{
40+
session.Delete("from EmployeeInfo");
41+
session.Delete("from Employee");
42+
tx.Commit();
43+
}
44+
}
45+
46+
[Test]
47+
public void TestOrphanedWhileManaged()
48+
{
49+
long empId = 0;
50+
51+
using (var s = OpenSession())
52+
using (var t = s.BeginTransaction())
53+
{
54+
var empInfoResults = s.CreateQuery("from EmployeeInfo").List<EmployeeInfo>();
55+
Assert.AreEqual(1, empInfoResults.Count);
56+
57+
var empResults = s.CreateQuery("from Employee").List<Employee>();
58+
Assert.AreEqual(1, empResults.Count);
59+
60+
var emp = empResults[0];
61+
Assert.NotNull(emp);
62+
63+
empId = emp.Id;
64+
emp.Info = null;
65+
t.Commit();
66+
}
67+
68+
using (var s = OpenSession())
69+
using (var t = s.BeginTransaction())
70+
{
71+
var emp = s.Get<Employee>(empId);
72+
Assert.Null(emp.Info);
73+
74+
var empInfoResults = s.CreateQuery("from EmployeeInfo").List<EmployeeInfo>();
75+
Assert.AreEqual(0, empInfoResults.Count);
76+
77+
var empResults = s.CreateQuery("from Employee").List<Employee>();
78+
Assert.AreEqual(1, empResults.Count);
79+
80+
t.Commit();
81+
}
82+
}
83+
}
84+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
assembly="NHibernate.Test"
4+
namespace="NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Bidirectional" >
5+
6+
<class name="Employee">
7+
<id name="Id" type="long" column="Id" >
8+
<generator class="increment" />
9+
</id>
10+
<one-to-one name="Info"
11+
property-ref="EmployeeDetails"
12+
class="EmployeeInfo"
13+
constrained="false"
14+
cascade="all,delete-orphan" />
15+
</class>
16+
17+
<class name="EmployeeInfo">
18+
<id name="Id" type="long" column="Id" >
19+
<generator class="increment" />
20+
</id>
21+
<many-to-one name="EmployeeDetails"
22+
column="employee_id"
23+
unique="true"
24+
not-null="true" />
25+
</class>
26+
27+
</hibernate-mapping>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Bidirectional
2+
{
3+
public class Employee
4+
{
5+
public virtual long Id { get; set; }
6+
public virtual EmployeeInfo Info { get; set; }
7+
8+
public Employee()
9+
{
10+
11+
}
12+
}
13+
14+
public class EmployeeInfo
15+
{
16+
public virtual long Id { get; set; }
17+
public virtual Employee EmployeeDetails { get; set; }
18+
19+
public EmployeeInfo()
20+
{
21+
22+
}
23+
24+
public EmployeeInfo(Employee emp)
25+
{
26+
EmployeeDetails = emp;
27+
}
28+
}
29+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using NUnit.Framework;
2+
using System.Collections;
3+
4+
namespace NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Composite
5+
{
6+
[TestFixture]
7+
public class DeleteOneToOneOrphansTest : TestCase
8+
{
9+
protected override string MappingsAssembly
10+
{
11+
get { return "NHibernate.Test"; }
12+
}
13+
14+
protected override IList Mappings
15+
{
16+
get { return new string[] { "Cascade.OneToOneCascadeDelete.Hbm.Fk.Composite.Mappings.hbm.xml" }; }
17+
}
18+
19+
protected override void OnSetUp()
20+
{
21+
base.OnSetUp();
22+
using (var s = OpenSession())
23+
using (var t = s.BeginTransaction())
24+
{
25+
var emp = new Employee();
26+
emp.Info = new EmployeeInfo( 1L, 1L);
27+
28+
s.Save(emp.Info);
29+
s.Save(emp);
30+
t.Commit();
31+
}
32+
}
33+
34+
protected override void OnTearDown()
35+
{
36+
base.OnTearDown();
37+
38+
using (var session = OpenSession())
39+
using (var tx = session.BeginTransaction())
40+
{
41+
session.Delete("from EmployeeInfo");
42+
session.Delete("from Employee");
43+
tx.Commit();
44+
}
45+
}
46+
47+
[Test]
48+
public void TestOrphanedWhileManaged()
49+
{
50+
long empId = 0;
51+
52+
using (var s = OpenSession())
53+
using (var t = s.BeginTransaction())
54+
{
55+
var infoList = s.CreateQuery("from EmployeeInfo").List<EmployeeInfo>();
56+
Assert.AreEqual(1, infoList.Count );
57+
58+
var empList = s.CreateQuery("from Employee").List<Employee>();
59+
Assert.AreEqual(1, empList.Count);
60+
61+
var emp = empList[0];
62+
Assert.NotNull(emp.Info);
63+
64+
empId = emp.Id;
65+
emp.Info = null;
66+
67+
t.Commit();
68+
}
69+
70+
using (var s = OpenSession())
71+
using (var t = s.BeginTransaction())
72+
{
73+
var emp = s.Get<Employee>(empId);
74+
Assert.IsNull(emp.Info);
75+
76+
var empInfoList = s.CreateQuery("from EmployeeInfo").List<EmployeeInfo>();
77+
Assert.AreEqual(0, empInfoList.Count);
78+
79+
var empList = s.CreateQuery("from Employee").List<Employee>();
80+
Assert.AreEqual(1, empList.Count);
81+
}
82+
}
83+
}
84+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
assembly="NHibernate.Test"
4+
namespace="NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Composite">
5+
6+
<class name="Employee">
7+
<id name="Id" type="long" column="Id" >
8+
<generator class="increment" />
9+
</id>
10+
<many-to-one name="Info"
11+
unique="true"
12+
not-found="exception"
13+
cascade="all,delete-orphan" >
14+
<column name="COMP_ID" />
15+
<column name="PERS_ID" />
16+
</many-to-one>
17+
</class>
18+
19+
<class name="EmployeeInfo">
20+
<composite-id class="EmployeeInfo+Identifier" name="Id" >
21+
<key-property name="CompanyId" column="COMP_ID" />
22+
<key-property name="PersonId" column="PERS_ID" />
23+
</composite-id>
24+
</class>
25+
26+
</hibernate-mapping>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
3+
namespace NHibernate.Test.Cascade.OneToOneCascadeDelete.Hbm.Fk.Composite
4+
{
5+
public class Employee
6+
{
7+
public virtual long Id { get; set; }
8+
public virtual EmployeeInfo Info { get; set; }
9+
10+
public Employee()
11+
{
12+
13+
}
14+
}
15+
16+
public class EmployeeInfo
17+
{
18+
public class Identifier
19+
{
20+
public virtual long CompanyId { get; set; }
21+
public virtual long PersonId { get; set; }
22+
23+
public Identifier()
24+
{
25+
26+
}
27+
28+
public Identifier(long companyId, long personId)
29+
{
30+
this.CompanyId = companyId;
31+
this.PersonId = personId;
32+
}
33+
34+
35+
public override bool Equals(Object o)
36+
{
37+
if (this == o)
38+
{
39+
return true;
40+
}
41+
42+
var t = this.GetType();
43+
var u = o.GetType();
44+
45+
46+
if (o == null || !t.IsAssignableFrom(u) || !u.IsAssignableFrom(t))
47+
{
48+
return false;
49+
}
50+
51+
var id = o as Identifier;
52+
53+
return CompanyId.Equals(id.CompanyId)
54+
&& PersonId.Equals(id.PersonId);
55+
56+
}
57+
58+
public override int GetHashCode()
59+
{
60+
return (31 * CompanyId.GetHashCode()) + PersonId.GetHashCode();
61+
}
62+
}
63+
64+
public virtual Identifier Id { get; set; }
65+
public virtual Employee Employee { get; set; }
66+
67+
public EmployeeInfo()
68+
{
69+
70+
}
71+
72+
public EmployeeInfo(long companyId, long personId)
73+
{
74+
this.Id = new Identifier(companyId, personId);
75+
}
76+
77+
public EmployeeInfo(Identifier id)
78+
{
79+
this.Id = id;
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)