|
From: <fab...@us...> - 2008-11-12 02:40:25
|
Revision: 3907
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3907&view=rev
Author: fabiomaulo
Date: 2008-11-12 02:40:14 +0000 (Wed, 12 Nov 2008)
Log Message:
-----------
Tests for session.Merge
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate.Test/Operations/
trunk/nhibernate/src/NHibernate.Test/Operations/AbstractOperationTestCase.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Address.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Competition.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Competition.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Operations/Competitor.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Employee.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Employer.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Employer.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Operations/MergeFixture.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Node.cs
trunk/nhibernate/src/NHibernate.Test/Operations/Node.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Operations/NumberedNode.cs
trunk/nhibernate/src/NHibernate.Test/Operations/OneToOne.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Operations/OptLockEntity.hbm.xml
trunk/nhibernate/src/NHibernate.Test/Operations/Person.cs
trunk/nhibernate/src/NHibernate.Test/Operations/PersonalDetails.cs
trunk/nhibernate/src/NHibernate.Test/Operations/TimestampedEntity.cs
trunk/nhibernate/src/NHibernate.Test/Operations/VersionedEntity.cs
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-10 17:47:28 UTC (rev 3906)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-12 02:40:14 UTC (rev 3907)
@@ -767,6 +767,19 @@
<Compile Include="Ondelete\ParentChildFixture.cs" />
<Compile Include="Ondelete\Person.cs" />
<Compile Include="Ondelete\Salesperson.cs" />
+ <Compile Include="Operations\AbstractOperationTestCase.cs" />
+ <Compile Include="Operations\Address.cs" />
+ <Compile Include="Operations\Competition.cs" />
+ <Compile Include="Operations\Competitor.cs" />
+ <Compile Include="Operations\Employee.cs" />
+ <Compile Include="Operations\Employer.cs" />
+ <Compile Include="Operations\MergeFixture.cs" />
+ <Compile Include="Operations\Node.cs" />
+ <Compile Include="Operations\NumberedNode.cs" />
+ <Compile Include="Operations\Person.cs" />
+ <Compile Include="Operations\PersonalDetails.cs" />
+ <Compile Include="Operations\TimestampedEntity.cs" />
+ <Compile Include="Operations\VersionedEntity.cs" />
<Compile Include="ProjectionFixtures\Key.cs" />
<Compile Include="ProjectionFixtures\Fixture.cs" />
<Compile Include="ProjectionFixtures\NodeType.cs" />
@@ -1520,6 +1533,11 @@
<EmbeddedResource Include="Cascade\JobBatch.hbm.xml" />
<EmbeddedResource Include="Deletetransient\Person.hbm.xml" />
<Content Include="DynamicEntity\package.html" />
+ <EmbeddedResource Include="Operations\Competition.hbm.xml" />
+ <EmbeddedResource Include="Operations\Employer.hbm.xml" />
+ <EmbeddedResource Include="Operations\Node.hbm.xml" />
+ <EmbeddedResource Include="Operations\OneToOne.hbm.xml" />
+ <EmbeddedResource Include="Operations\OptLockEntity.hbm.xml" />
<EmbeddedResource Include="Subclass\EnumDiscriminator\EnumDiscriminator.hbm.xml" />
<EmbeddedResource Include="Generatedkeys\Select\MyEntity.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1478\Mappings.hbm.xml" />
Added: trunk/nhibernate/src/NHibernate.Test/Operations/AbstractOperationTestCase.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/AbstractOperationTestCase.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/AbstractOperationTestCase.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,58 @@
+using System.Collections;
+using NHibernate.Cfg;
+using NUnit.Framework;
+using NUnit.Framework.SyntaxHelpers;
+
+namespace NHibernate.Test.Operations
+{
+ public abstract class AbstractOperationTestCase : TestCase
+ {
+ protected override string MappingsAssembly
+ {
+ get { return "NHibernate.Test"; }
+ }
+
+ protected override IList Mappings
+ {
+ get
+ {
+ return new[]
+ {
+ "Operations.Node.hbm.xml", "Operations.Employer.hbm.xml", "Operations.OptLockEntity.hbm.xml",
+ "Operations.OneToOne.hbm.xml", "Operations.Competition.hbm.xml"
+ };
+ }
+ }
+
+ protected override string CacheConcurrencyStrategy
+ {
+ get { return null; }
+ }
+
+ protected override void Configure(Configuration configuration)
+ {
+ configuration.SetProperty(Environment.GenerateStatistics, "true");
+ configuration.SetProperty(Environment.BatchSize, "0");
+ }
+
+ protected void ClearCounts()
+ {
+ sessions.Statistics.Clear();
+ }
+
+ protected void AssertInsertCount(long expected)
+ {
+ Assert.That(sessions.Statistics.EntityInsertCount, Is.EqualTo(expected), "unexpected insert count");
+ }
+
+ protected void AssertUpdateCount(int expected)
+ {
+ Assert.That(sessions.Statistics.EntityUpdateCount, Is.EqualTo(expected), "unexpected update count");
+ }
+
+ protected void AssertDeleteCount(int expected)
+ {
+ Assert.That(sessions.Statistics.EntityDeleteCount, Is.EqualTo(expected), "unexpected delete count");
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Address.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Address.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Address.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,21 @@
+namespace NHibernate.Test.Operations
+{
+ public class Address
+ {
+ private Person resident;
+ public virtual long Id { get; set; }
+ public virtual string StreetAddress { get; set; }
+ public virtual string City { get; set; }
+ public virtual string Country { get; set; }
+
+ public virtual Person Resident
+ {
+ get { return resident; }
+ set
+ {
+ resident = value;
+ resident.Address = this;
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Competition.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Competition.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Competition.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class Competition
+ {
+ public Competition()
+ {
+ Competitors = new List<Competitor>();
+ }
+ public virtual int Id { get; set; }
+ public virtual IList<Competitor> Competitors { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Competition.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Competition.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Competition.hbm.xml 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Operations">
+
+ <class name="Competition">
+ <id name="Id">
+ <generator class="native"/>
+ </id>
+ <list name="Competitors" table="COMPET_ION_OR" cascade="persist,merge,delete">
+ <key column="TION_ID"/>
+ <list-index column="INDEX_COL"/>
+ <many-to-many class="Competitor" column="TOR_ID" />
+ </list>
+ </class>
+
+ <class name="Competitor">
+ <id name="Id">
+ <generator class="native"/>
+ </id>
+ <property name="Name"/>
+ </class>
+
+</hibernate-mapping>
+
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Competitor.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Competitor.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Competitor.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,8 @@
+namespace NHibernate.Test.Operations
+{
+ public class Competitor
+ {
+ public virtual int Id { get; set; }
+ public virtual string Name { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Employee.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Employee.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Employee.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class Employee
+ {
+ public virtual int Id { get; set; }
+ public virtual ICollection<Employer> Employers { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Employer.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Employer.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Employer.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class Employer
+ {
+ public virtual int Id { get; set; }
+ public virtual ICollection<Employee> Employees { get; set; }
+ public virtual int Vers { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Employer.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Employer.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Employer.hbm.xml 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Operations">
+
+ <class name="Employer" polymorphism="explicit">
+ <id name="Id">
+ <generator class="native"/>
+ </id>
+ <version column="vers" name="Vers"/>
+ <bag name="Employees" cascade="persist,merge" table="EMPLOYER_EMPLOYEE">
+ <key column="EMPER_ID"/>
+ <many-to-many class="Employee" column="EMPEE_ID" />
+ </bag>
+ </class>
+
+ <class name="Employee" polymorphism="explicit">
+ <id name="Id">
+ <generator class="native"/>
+ </id>
+ <bag name="Employers" inverse="true" cascade="persist,merge,save-update" table="EMPLOYER_EMPLOYEE">
+ <key column="EMPEE_ID"/>
+ <many-to-many class="Employer" column="EMPER_ID" />
+ </bag>
+ </class>
+
+</hibernate-mapping>
+
Added: trunk/nhibernate/src/NHibernate.Test/Operations/MergeFixture.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/MergeFixture.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/MergeFixture.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,705 @@
+using System.Collections.Generic;
+using NHibernate.Criterion;
+using NUnit.Framework;
+using NUnit.Framework.SyntaxHelpers;
+
+namespace NHibernate.Test.Operations
+{
+ [TestFixture]
+ public class MergeFixture : AbstractOperationTestCase
+ {
+ protected override void OnTearDown()
+ {
+ Cleanup();
+ }
+
+ private void Cleanup()
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ s.Delete("from NumberedNode where parent is not null");
+ s.Delete("from NumberedNode");
+
+ s.Delete("from Node where parent is not null");
+ s.Delete("from Node");
+
+ s.Delete("from VersionedEntity where parent is not null");
+ s.Delete("from VersionedEntity");
+ s.Delete("from TimestampedEntity");
+
+ s.Delete("from Competitor");
+ s.Delete("from Competition");
+
+ s.Delete("from Employer");
+
+ tx.Commit();
+ }
+ }
+ }
+
+ [Test]
+ public void DeleteAndMerge()
+ {
+ using (ISession s = OpenSession())
+ {
+ s.BeginTransaction();
+ var jboss = new Employer();
+ s.Persist(jboss);
+ s.Transaction.Commit();
+ s.Clear();
+
+ s.BeginTransaction();
+ var otherJboss = s.Get<Employer>(jboss.Id);
+ s.Delete(otherJboss);
+ s.Transaction.Commit();
+ s.Clear();
+ jboss.Vers = 1;
+ s.BeginTransaction();
+ s.Merge(jboss);
+ s.Transaction.Commit();
+ }
+ }
+
+ [Test]
+ public void MergeBidiForeignKeyOneToOne()
+ {
+ Person p;
+ Address a;
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ p = new Person {Name = "steve"};
+ a = new Address {StreetAddress = "123 Main", City = "Austin", Country = "US", Resident = p};
+ s.Persist(a);
+ s.Persist(p);
+ tx.Commit();
+ }
+ }
+
+ ClearCounts();
+
+ p.Address.StreetAddress = "321 Main";
+
+ using (ISession s = OpenSession())
+ {
+ using (s.BeginTransaction())
+ {
+ p = (Person) s.Merge(p);
+ s.Transaction.Commit();
+ }
+ }
+
+ AssertInsertCount(0);
+ AssertUpdateCount(0); // no cascade
+ AssertDeleteCount(0);
+
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ s.Delete(a);
+ s.Delete(p);
+ tx.Commit();
+ }
+ }
+ }
+
+ [Test, Ignore("Need some more investigation about id sync.")]
+ public void MergeBidiPrimayKeyOneToOne()
+ {
+ Person p;
+ using (ISession s = OpenSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ p = new Person {Name = "steve"};
+ new PersonalDetails {SomePersonalDetail = "I have big feet", Person = p};
+ s.Persist(p);
+ tx.Commit();
+ }
+
+ ClearCounts();
+
+ p.Details.SomePersonalDetail = p.Details.SomePersonalDetail + " and big hands too";
+ using (ISession s = OpenSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ p = (Person) s.Merge(p);
+ tx.Commit();
+ }
+
+ AssertInsertCount(0);
+ AssertUpdateCount(1);
+ AssertDeleteCount(0);
+
+ using (ISession s = OpenSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ s.Delete(p);
+ tx.Commit();
+ }
+ }
+
+ [Test]
+ public void MergeDeepTree()
+ {
+ ClearCounts();
+
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var root = new Node {Name = "root"};
+ var child = new Node {Name = "child"};
+ var grandchild = new Node {Name = "grandchild"};
+ root.AddChild(child);
+ child.AddChild(grandchild);
+ s.Merge(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(3);
+ AssertUpdateCount(0);
+ ClearCounts();
+
+ grandchild.Description = "the grand child";
+ var grandchild2 = new Node {Name = "grandchild2"};
+ child.AddChild(grandchild2);
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ s.Merge(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(1);
+ AssertUpdateCount(1);
+ ClearCounts();
+
+ var child2 = new Node {Name = "child2"};
+ var grandchild3 = new Node {Name = "grandchild3"};
+ child2.AddChild(grandchild3);
+ root.AddChild(child2);
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ s.Merge(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(2);
+ AssertUpdateCount(0);
+ ClearCounts();
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ s.Delete(grandchild);
+ s.Delete(grandchild2);
+ s.Delete(grandchild3);
+ s.Delete(child);
+ s.Delete(child2);
+ s.Delete(root);
+ tx.Commit();
+ s.Close();
+ }
+
+ [Test]
+ public void MergeDeepTreeWithGeneratedId()
+ {
+ ClearCounts();
+
+ NumberedNode root;
+ NumberedNode child;
+ NumberedNode grandchild;
+ using (ISession s = OpenSession())
+ {
+ ITransaction tx = s.BeginTransaction();
+ root = new NumberedNode("root");
+ child = new NumberedNode("child");
+ grandchild = new NumberedNode("grandchild");
+ root.AddChild(child);
+ child.AddChild(grandchild);
+ root = (NumberedNode) s.Merge(root);
+ tx.Commit();
+ }
+
+ AssertInsertCount(3);
+ AssertUpdateCount(0);
+ ClearCounts();
+
+ IEnumerator<NumberedNode> rit = root.Children.GetEnumerator();
+ rit.MoveNext();
+ child = rit.Current;
+ IEnumerator<NumberedNode> cit = child.Children.GetEnumerator();
+ cit.MoveNext();
+ grandchild = cit.Current;
+ grandchild.Description = "the grand child";
+ var grandchild2 = new NumberedNode("grandchild2");
+ child.AddChild(grandchild2);
+
+ using (ISession s = OpenSession())
+ {
+ ITransaction tx = s.BeginTransaction();
+ root = (NumberedNode) s.Merge(root);
+ tx.Commit();
+ }
+
+ AssertInsertCount(1);
+ AssertUpdateCount(1);
+ ClearCounts();
+
+ sessions.Evict(typeof (NumberedNode));
+
+ var child2 = new NumberedNode("child2");
+ var grandchild3 = new NumberedNode("grandchild3");
+ child2.AddChild(grandchild3);
+ root.AddChild(child2);
+
+ using (ISession s = OpenSession())
+ {
+ ITransaction tx = s.BeginTransaction();
+ root = (NumberedNode) s.Merge(root);
+ tx.Commit();
+ }
+
+ AssertInsertCount(2);
+ AssertUpdateCount(0);
+ ClearCounts();
+
+ using (ISession s = OpenSession())
+ {
+ ITransaction tx = s.BeginTransaction();
+ s.Delete("from NumberedNode where name like 'grand%'");
+ s.Delete("from NumberedNode where name like 'child%'");
+ s.Delete("from NumberedNode");
+ tx.Commit();
+ }
+ }
+
+ [Test]
+ public void MergeManaged()
+ {
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var root = new NumberedNode("root");
+ s.Persist(root);
+ tx.Commit();
+
+ ClearCounts();
+
+ tx = s.BeginTransaction();
+ var child = new NumberedNode("child");
+ root.AddChild(child);
+ Assert.That(s.Merge(root), Is.SameAs(root));
+ IEnumerator<NumberedNode> rit = root.Children.GetEnumerator();
+ rit.MoveNext();
+ NumberedNode mergedChild = rit.Current;
+ Assert.That(mergedChild, Is.Not.SameAs(child));
+ Assert.That(s.Contains(mergedChild));
+ Assert.That(! s.Contains(child));
+ Assert.That(root.Children.Count, Is.EqualTo(1));
+ Assert.That(root.Children.Contains(mergedChild));
+ //assertNotSame( mergedChild, s.Merge(child) ); //yucky :(
+ tx.Commit();
+
+ AssertInsertCount(1);
+ AssertUpdateCount(0);
+
+ Assert.That(root.Children.Count, Is.EqualTo(1));
+ Assert.That(root.Children.Contains(mergedChild));
+
+ tx = s.BeginTransaction();
+ Assert.That(s.CreateCriteria(typeof (NumberedNode)).SetProjection(Projections.RowCount()).UniqueResult(),
+ Is.EqualTo(2));
+ tx.Rollback();
+ s.Close();
+ }
+
+ [Test]
+ public void MergeManyToManyWithCollectionDeference()
+ {
+ // setup base data...
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var competition = new Competition();
+ competition.Competitors.Add(new Competitor {Name = "Name"});
+ competition.Competitors.Add(new Competitor());
+ competition.Competitors.Add(new Competitor());
+ s.Persist(competition);
+ tx.Commit();
+ s.Close();
+
+ // the competition graph is now detached:
+ // 1) create a new List reference to represent the competitors
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ var newComp = new List<Competitor>();
+ Competitor originalCompetitor = competition.Competitors[0];
+ originalCompetitor.Name = "Name2";
+ newComp.Add(originalCompetitor);
+ newComp.Add(new Competitor());
+ // 2) set that new List reference unto the Competition reference
+ competition.Competitors = newComp;
+ // 3) attempt the merge
+ var competition2 = (Competition) s.Merge(competition);
+ tx.Commit();
+ s.Close();
+
+ Assert.That(!(competition == competition2));
+ Assert.That(!(competition.Competitors == competition2.Competitors));
+ Assert.That(competition2.Competitors.Count, Is.EqualTo(2));
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ competition = s.Get<Competition>(competition.Id);
+ Assert.That(competition.Competitors.Count, Is.EqualTo(2));
+ s.Delete(competition);
+ tx.Commit();
+ s.Close();
+ }
+
+ [Test]
+ public void MergeStaleVersionFails()
+ {
+ ISession s = OpenSession();
+ s.BeginTransaction();
+ var entity = new VersionedEntity {Id = "entity", Name = "entity"};
+ s.Persist(entity);
+ s.Transaction.Commit();
+ s.Close();
+
+ // make the detached 'entity' reference stale...
+ s = OpenSession();
+ s.BeginTransaction();
+ var entity2 = s.Get<VersionedEntity>(entity.Id);
+ entity2.Name = "entity-name";
+ s.Transaction.Commit();
+ s.Close();
+
+ // now try to reattch it
+ s = OpenSession();
+ s.BeginTransaction();
+ try
+ {
+ s.Merge(entity);
+ s.Transaction.Commit();
+ Assert.Fail("was expecting staleness error");
+ }
+ catch (StaleObjectStateException)
+ {
+ // expected outcome...
+ }
+ finally
+ {
+ s.Transaction.Rollback();
+ s.Close();
+ Cleanup();
+ }
+ }
+
+ [Test]
+ public void MergeTree()
+ {
+ ClearCounts();
+
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var root = new Node {Name = "root"};
+ var child = new Node {Name = "child"};
+ root.AddChild(child);
+ s.Persist(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(2);
+ ClearCounts();
+
+ root.Description = "The root node";
+ child.Description = "The child node";
+
+ var secondChild = new Node {Name = "second child"};
+
+ root.AddChild(secondChild);
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ s.Merge(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(1);
+ AssertUpdateCount(2);
+ }
+
+ [Test]
+ public void MergeTreeWithGeneratedId()
+ {
+ ClearCounts();
+
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var root = new NumberedNode("root");
+ var child = new NumberedNode("child");
+ root.AddChild(child);
+ s.Persist(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(2);
+ ClearCounts();
+
+ root.Description = "The root node";
+ child.Description = "The child node";
+
+ var secondChild = new NumberedNode("second child");
+
+ root.AddChild(secondChild);
+
+ s = OpenSession();
+ tx = s.BeginTransaction();
+ s.Merge(root);
+ tx.Commit();
+ s.Close();
+
+ AssertInsertCount(1);
+ AssertUpdateCount(2);
+ }
+
+ [Test]
+ public void NoExtraUpdatesOnMerge()
+ {
+ ISession s = OpenSession();
+ s.BeginTransaction();
+ var node = new Node {Name = "test"};
+ s.Persist(node);
+ s.Transaction.Commit();
+ s.Close();
+
+ ClearCounts();
+
+ // node is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ s = OpenSession();
+ s.BeginTransaction();
+ node = (Node) s.Merge(node);
+ s.Transaction.Commit();
+ s.Close();
+
+ AssertUpdateCount(0);
+ AssertInsertCount(0);
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ node.Description = "new description";
+ s = OpenSession();
+ s.BeginTransaction();
+ node = (Node) s.Merge(node);
+ s.Transaction.Commit();
+ s.Close();
+ AssertUpdateCount(1);
+ AssertInsertCount(0);
+ ///////////////////////////////////////////////////////////////////////
+ }
+
+ [Test]
+ public void NoExtraUpdatesOnMergeVersioned()
+ {
+ ISession s = OpenSession();
+ s.BeginTransaction();
+ var entity = new VersionedEntity {Id = "entity", Name = "entity"};
+ s.Persist(entity);
+ s.Transaction.Commit();
+ s.Close();
+
+ ClearCounts();
+
+ // entity is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ s = OpenSession();
+ s.BeginTransaction();
+ var mergedEntity = (VersionedEntity) s.Merge(entity);
+ s.Transaction.Commit();
+ s.Close();
+
+ AssertUpdateCount(0);
+ AssertInsertCount(0);
+ Assert.That(entity.Version, Is.EqualTo(mergedEntity.Version), "unexpected version increment");
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ entity.Name = "new name";
+ s = OpenSession();
+ s.BeginTransaction();
+ entity = (VersionedEntity) s.Merge(entity);
+ s.Transaction.Commit();
+ s.Close();
+ AssertUpdateCount(1);
+ AssertInsertCount(0);
+ ///////////////////////////////////////////////////////////////////////
+ }
+
+ [Test]
+ public void NoExtraUpdatesOnMergeVersionedWithCollection()
+ {
+ ISession s = OpenSession();
+ s.BeginTransaction();
+ var parent = new VersionedEntity {Id = "parent", Name = "parent"};
+ var child = new VersionedEntity {Id = "child", Name = "child"};
+ parent.Children.Add(child);
+ child.Parent = parent;
+ s.Persist(parent);
+ s.Transaction.Commit();
+ s.Close();
+
+ ClearCounts();
+
+ // parent is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ s = OpenSession();
+ s.BeginTransaction();
+ var mergedParent = (VersionedEntity) s.Merge(parent);
+ s.Transaction.Commit();
+ s.Close();
+
+ AssertUpdateCount(0);
+ AssertInsertCount(0);
+ Assert.That(parent.Version, Is.EqualTo(mergedParent.Version), "unexpected parent version increment");
+ IEnumerator<VersionedEntity> it = mergedParent.Children.GetEnumerator();
+ it.MoveNext();
+ VersionedEntity mergedChild = it.Current;
+ Assert.That(child.Version, Is.EqualTo(mergedChild.Version), "unexpected child version increment");
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ mergedParent.Name = "new name";
+ mergedParent.Children.Add(new VersionedEntity {Id = "child2", Name = "new child"});
+ s = OpenSession();
+ s.BeginTransaction();
+ parent = (VersionedEntity) s.Merge(mergedParent);
+ s.Transaction.Commit();
+ s.Close();
+ AssertUpdateCount(1);
+ AssertInsertCount(1);
+ ///////////////////////////////////////////////////////////////////////
+ }
+
+ [Test]
+ public void NoExtraUpdatesOnMergeWithCollection()
+ {
+ ISession s = OpenSession();
+ s.BeginTransaction();
+ var parent = new Node {Name = "parent"};
+ var child = new Node {Name = "child"};
+ parent.Children.Add(child);
+ child.Parent = parent;
+ s.Persist(parent);
+ s.Transaction.Commit();
+ s.Close();
+
+ ClearCounts();
+
+ // parent is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ s = OpenSession();
+ s.BeginTransaction();
+ parent = (Node) s.Merge(parent);
+ s.Transaction.Commit();
+ s.Close();
+
+ AssertUpdateCount(0);
+ AssertInsertCount(0);
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ IEnumerator<Node> it = parent.Children.GetEnumerator();
+ it.MoveNext();
+ it.Current.Description = "child's new description";
+ parent.Children.Add(new Node {Name = "second child"});
+ s = OpenSession();
+ s.BeginTransaction();
+ parent = (Node) s.Merge(parent);
+ s.Transaction.Commit();
+ s.Close();
+ AssertUpdateCount(1);
+ AssertInsertCount(1);
+ ///////////////////////////////////////////////////////////////////////
+ }
+
+ [Test]
+ public void PersistThenMergeInSameTxnWithTimestamp()
+ {
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var entity = new TimestampedEntity {Id = "test", Name = "test"};
+ s.Persist(entity);
+ s.Merge(new TimestampedEntity {Id = "test", Name = "test-2"});
+
+ try
+ {
+ // control operation...
+ s.SaveOrUpdate(new TimestampedEntity {Id = "test", Name = "test-3"});
+ Assert.Fail("saveOrUpdate() should fail here");
+ }
+ catch (NonUniqueObjectException)
+ {
+ // expected behavior
+ }
+
+ tx.Commit();
+ s.Close();
+ }
+
+ [Test]
+ public void PersistThenMergeInSameTxnWithVersion()
+ {
+ ISession s = OpenSession();
+ ITransaction tx = s.BeginTransaction();
+ var entity = new VersionedEntity {Id = "test", Name = "test"};
+ s.Persist(entity);
+ s.Merge(new VersionedEntity {Id = "test", Name = "test-2"});
+
+ try
+ {
+ // control operation...
+ s.SaveOrUpdate(new VersionedEntity {Id = "test", Name = "test-3"});
+ Assert.Fail("saveOrUpdate() should fail here");
+ }
+ catch (NonUniqueObjectException)
+ {
+ // expected behavior
+ }
+
+ tx.Commit();
+ s.Close();
+ }
+
+ [Test]
+ public void RecursiveMergeTransient()
+ {
+ using (ISession s = OpenSession())
+ {
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ var jboss = new Employer();
+ var gavin = new Employee();
+ jboss.Employees = new List<Employee> {gavin};
+ s.Merge(jboss);
+ s.Flush();
+ jboss = s.CreateQuery("from Employer e join fetch e.Employees").UniqueResult<Employer>();
+ Assert.That(NHibernateUtil.IsInitialized(jboss.Employees));
+ Assert.That(jboss.Employees.Count, Is.EqualTo(1));
+ s.Clear();
+ IEnumerator<Employee> it = jboss.Employees.GetEnumerator();
+ it.MoveNext();
+
+ s.Merge(it.Current);
+ tx.Commit();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Node.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Node.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Node.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,43 @@
+using System;
+using Iesi.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class Node
+ {
+ private ISet<Node> cascadingChildren = new HashedSet<Node>();
+ private ISet<Node> children = new HashedSet<Node>();
+ private DateTime created = DateTime.Now;
+
+ public virtual string Name { get; set; }
+
+ public virtual string Description { get; set; }
+
+ public virtual DateTime Created
+ {
+ get { return created; }
+ set { created = value; }
+ }
+
+ public virtual Node Parent { get; set; }
+
+ public virtual ISet<Node> Children
+ {
+ get { return children; }
+ set { children = value; }
+ }
+
+ public virtual ISet<Node> CascadingChildren
+ {
+ get { return cascadingChildren; }
+ set { cascadingChildren = value; }
+ }
+
+ public virtual Node AddChild(Node child)
+ {
+ children.Add(child);
+ child.Parent = this;
+ return this;
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Node.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Node.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Node.hbm.xml 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Operations">
+
+ <class name="Node" polymorphism="explicit">
+ <id name="Name">
+ <generator class="assigned"/>
+ </id>
+ <property name="Description"/>
+ <many-to-one name="Parent"/>
+ <property name="Created" not-null="true"/>
+ <set name="Children" inverse="true" cascade="persist,merge,save-update,evict">
+ <key column="parent"/>
+ <one-to-many class="Node"/>
+ </set>
+ <set name="CascadingChildren" inverse="false" cascade="persist,merge,save-update,evict,delete">
+ <key column="CASC_PARENT"/>
+ <one-to-many class="Node"/>
+ </set>
+ </class>
+
+ <class name="NumberedNode" polymorphism="explicit">
+ <id name="Id" unsaved-value="0">
+ <generator class="native"/>
+ </id>
+ <property name="Name">
+ <column name="name" index="iname" not-null="true"/>
+ </property>
+ <property name="Description"/>
+ <property name="Created" not-null="true"/>
+ <many-to-one name="Parent" class="NumberedNode"/>
+ <set name="Children" inverse="true" cascade="persist,merge,save-update" access="field.camelcase">
+ <key column="parent"/>
+ <one-to-many class="NumberedNode"/>
+ </set>
+ </class>
+
+</hibernate-mapping>
+
Added: trunk/nhibernate/src/NHibernate.Test/Operations/NumberedNode.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/NumberedNode.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/NumberedNode.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using Iesi.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class NumberedNode
+ {
+ private readonly ISet<NumberedNode> children = new HashedSet<NumberedNode>();
+
+ protected NumberedNode() {}
+
+ public NumberedNode(string name)
+ {
+ Name = name;
+ Created = DateTime.Now;
+ }
+
+ public virtual long Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual NumberedNode Parent { get; set; }
+
+ public virtual ICollection<NumberedNode> Children
+ {
+ get { return children; }
+ }
+
+ public virtual string Description { get; set; }
+ public virtual DateTime Created { get; set; }
+
+ public virtual NumberedNode AddChild(NumberedNode child)
+ {
+ children.Add(child);
+ child.Parent = this;
+ return this;
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/OneToOne.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/OneToOne.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/OneToOne.hbm.xml 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ Mappings demonstrating bidirectional one-to-one mappings for testing
+ with various operations.
+
+ Person -> Address is modeled as a bidirectional one to one based on FK.
+ Person -> Details is modeled as a bidirectional one to one based on PK.
+-->
+
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Operations">
+
+ <class name="Person" table="OPS_PERSON">
+ <id name="Id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="Name" column="NAME" type="string"/>
+ <one-to-one name="Address" class="Address" property-ref="Resident" />
+ <one-to-one name="Details" class="PersonalDetails" cascade="all" />
+ </class>
+
+ <class name="Address" table="OPS_ADDRESS">
+ <id name="Id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="StreetAddress" column="STREET" type="string" />
+ <property name="City" column="CITY" type="string" />
+ <property name="Country" column="CTRY" type="string" />
+ <many-to-one name="Resident" column="RESIDENT" class="Person" />
+ </class>
+
+ <class name="PersonalDetails" table="OPS_PERS_DETAIL">
+ <id name="Id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="SomePersonalDetail" column="SOME_DETAIL" type="string"/>
+ <one-to-one name="Person" class="Person" constrained="true" />
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/OptLockEntity.hbm.xml
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/OptLockEntity.hbm.xml (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/OptLockEntity.hbm.xml 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ assembly="NHibernate.Test"
+ namespace="NHibernate.Test.Operations">
+
+ <class name="VersionedEntity" table="V_ENTITY">
+ <id name="Id" column="ID" type="string">
+ <generator class="assigned"/>
+ </id>
+ <version name="Version" column="VERS" type="long" />
+ <property name="Name" column="NAME" type="string" />
+ <many-to-one name="Parent" class="VersionedEntity"/>
+ <set name="Children" inverse="true" cascade="persist,merge,save-update,evict,delete">
+ <key column="parent"/>
+ <one-to-many class="VersionedEntity"/>
+ </set>
+ </class>
+
+ <class name="TimestampedEntity" table="T_ENTITY">
+ <id name="Id" column="ID" type="string">
+ <generator class="assigned"/>
+ </id>
+ <timestamp name="Timestamp" column="TS" />
+ <property name="Name" column="NAME" type="string" />
+ </class>
+
+</hibernate-mapping>
+
Added: trunk/nhibernate/src/NHibernate.Test/Operations/Person.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/Person.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/Person.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,10 @@
+namespace NHibernate.Test.Operations
+{
+ public class Person
+ {
+ public virtual long Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual Address Address { get; set; }
+ public virtual PersonalDetails Details { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/PersonalDetails.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/PersonalDetails.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/PersonalDetails.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,19 @@
+namespace NHibernate.Test.Operations
+{
+ public class PersonalDetails
+ {
+ private Person person;
+ public virtual long Id { get; set; }
+ public virtual string SomePersonalDetail { get; set; }
+
+ public virtual Person Person
+ {
+ get { return person; }
+ set
+ {
+ person = value;
+ person.Details = this;
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/TimestampedEntity.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/TimestampedEntity.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/TimestampedEntity.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,11 @@
+using System;
+
+namespace NHibernate.Test.Operations
+{
+ public class TimestampedEntity
+ {
+ public virtual string Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual DateTime Timestamp { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/Operations/VersionedEntity.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/Operations/VersionedEntity.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/Operations/VersionedEntity.cs 2008-11-12 02:40:14 UTC (rev 3907)
@@ -0,0 +1,18 @@
+using Iesi.Collections.Generic;
+
+namespace NHibernate.Test.Operations
+{
+ public class VersionedEntity
+ {
+ public VersionedEntity()
+ {
+ Children = new HashedSet<VersionedEntity>();
+ }
+
+ public virtual string Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual long Version { get; set; }
+ public virtual VersionedEntity Parent { get; set; }
+ public virtual ISet<VersionedEntity> Children { get; set; }
+ }
+}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|