From: <fab...@us...> - 2009-06-04 23:32:04
|
Revision: 4411 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4411&view=rev Author: fabiomaulo Date: 2009-06-04 23:31:55 +0000 (Thu, 04 Jun 2009) Log Message: ----------- Test for NH-1810 (smell as external issue) Modified Paths: -------------- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Child.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Children.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Disease.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Doctor.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/MedicalRecord.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Parent.cs Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Child.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Child.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Child.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,66 @@ +using System; +using log4net; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public class Child : IComparable<Child> + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int id; + int age; + Parent parent; + + public virtual int Id + { + get { return id; } + } + + public virtual int Age + { + get { return age; } + set { age = value; } + } + + public virtual Parent Parent + { + get { return parent; } + set { parent = value; } + } + + public virtual bool Equals(Child other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Age == Age && Equals(other.Parent, Parent); + } + + public virtual int CompareTo(Child other) + { + return Id.CompareTo(other.Id); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Child)) return false; + return Equals((Child) obj); + } + + int? hashCode; + + public override int GetHashCode() + { + Log.Debug("Child.GetHashCode()"); + + if (!hashCode.HasValue) + unchecked + { + hashCode = (Age*397) ^ (Parent != null ? Parent.GetHashCode() : 0); + } + + return hashCode.Value; + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Children.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Children.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Children.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,160 @@ +using System.Collections; +using System.Collections.Generic; +using Iesi.Collections.Generic; +using NHibernate.Collection; +using NHibernate.Collection.Generic; +using NHibernate.Engine; +using NHibernate.Persister.Collection; +using NHibernate.UserTypes; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public interface IChildrenBehaviour + { + void AddChild(Child child); + } + + public class ChildrenBehaviour : IChildrenBehaviour + { + private readonly ISet<Child> children; + + public ChildrenBehaviour(ISet<Child> children) + { + this.children = children; + } + + public void AddChild(Child child) + { + children.Add(child); + } + } + + public interface IChildren : IChildrenBehaviour + { + } + + // Using a HashedSet<Child> instead SortedSet<Child> all work fine. + public class Children : SortedSet<Child>, IChildren + { + private readonly IChildrenBehaviour behaviour; + + public Children() + { + behaviour = new ChildrenBehaviour(this); + } + + public Children(IComparer<Child> comparer) : base(comparer) + { + behaviour = new ChildrenBehaviour(this); + } + + public Children(ICollection<Child> initialValues) : base(initialValues) + { + behaviour = new ChildrenBehaviour(this); + } + + public Children(ICollection initialValues) : base(initialValues) + { + behaviour = new ChildrenBehaviour(this); + } + + public Children(ICollection<Child> initialValues, IComparer<Child> comparer) : base(initialValues, comparer) + { + behaviour = new ChildrenBehaviour(this); + } + + public void AddChild(Child child) + { + behaviour.AddChild(child); + } + } + + public class PersistentChildren : PersistentGenericSet<Child>, IChildren + { + private readonly IChildrenBehaviour behaviour; + + public PersistentChildren(ISessionImplementor session) + : base(session) + { + behaviour = new ChildrenBehaviour(this); + } + + public PersistentChildren(ISessionImplementor session, ISet<Child> collection) + : base(session, collection) + { + behaviour = new ChildrenBehaviour(this); + } + + public void AddChild(Child child) + { + behaviour.AddChild(child); + } + } + + public class Factory : SetFactory<Child> + { + public override IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister) + { + return new PersistentChildren(session); + } + + public override IPersistentCollection Wrap(ISessionImplementor session, object collection) + { + return new PersistentChildren(session, (ISet<Child>)collection); + } + + protected override object Instantiate() + { + return new Children(); + } + } + + public class SetFactory<T> : IUserCollectionType + { + public virtual IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister) + { + return new PersistentGenericSet<T>(session); + } + + public virtual IPersistentCollection Wrap(ISessionImplementor session, object collection) + { + return new PersistentGenericSet<T>(session, (ISet<T>)collection); + } + + public IEnumerable GetElements(object collection) + { + return (IEnumerable)collection; + } + + public bool Contains(object collection, object entity) + { + return ((ISet<T>)collection).Contains((T)entity); + } + + public object IndexOf(object collection, object entity) + { + return new List<T>((ISet<T>)collection).IndexOf((T)entity); + } + + public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session) + { + var result = (ISet<T>)target; + result.Clear(); + + foreach (var o in (IEnumerable)original) + result.Add((T)o); + + return result; + } + + public object Instantiate(int anticipatedSize) + { + return Instantiate(); + } + + protected virtual object Instantiate() + { + return new HashedSet<T>(); + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Disease.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Disease.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Disease.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,70 @@ +using log4net; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public class Disease + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int id; + string name; + int duration; + MedicalRecord medicalRecord; + + public virtual int Id + { + get { return id; } + } + + public virtual string Name + { + get { return name; } + set { name = value; } + } + + public virtual int Duration + { + get { return duration; } + set { duration = value; } + } + + public virtual MedicalRecord MedicalRecord + { + get { return medicalRecord; } + set { medicalRecord = value; } + } + + public virtual bool Equals(Disease other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.Name, Name) && other.Duration == Duration && Equals(other.MedicalRecord, MedicalRecord); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Disease)) return false; + return Equals((Disease) obj); + } + + int? hashCode; + + public override int GetHashCode() + { + Log.Debug("Disease.GetHashCode()"); + + if (!hashCode.HasValue) + unchecked + { + int result = (Name != null ? Name.GetHashCode() : 0); + result = (result*397) ^ Duration; + result = (result*397) ^ (MedicalRecord != null ? MedicalRecord.GetHashCode() : 0); + hashCode = result; + } + + return hashCode.Value; + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Doctor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Doctor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Doctor.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,57 @@ +using log4net; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public class Doctor + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int id; + MedicalRecord medicalRecord; + int doctorNumber; + + public virtual int Id + { + get { return id; } + } + + public virtual MedicalRecord MedicalRecord + { + get { return medicalRecord; } + set { medicalRecord = value; } + } + + public virtual int DoctorNumber + { + get { return doctorNumber; } + set { doctorNumber = value; } + } + + public virtual bool Equals(Doctor other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.doctorNumber == doctorNumber; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Doctor)) return false; + return Equals((Doctor) obj); + } + + int? hashCode; + + public override int GetHashCode() + { + Log.Debug("Doctor.GetHashCode()"); + + if (!hashCode.HasValue) + hashCode = doctorNumber.GetHashCode(); + + return hashCode.Value; + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Fixture.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,93 @@ +using System.Data; +using log4net; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + [TestFixture, Ignore("To investigate.")] + public class Fixture : BugTestCase + { + // The problem is the same using a default sort="natural" collection for Children + // and there is no problem using a default HashedSet. + // look a the implementation of Children + + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int parentId; + int doctorId; + + protected override ISession OpenSession() + { + var session = base.OpenSession(); + session.FlushMode = FlushMode.Commit; + + return session; + } + + protected override void OnSetUp() + { + using (ISession sess = OpenSession()) + using (ITransaction tx = sess.BeginTransaction()) + { + var parent = new Parent {Address = "A street, A town, A country"}; + + // If you add a child all work fine. + //var child = new Child {Age = 2, Parent = parent}; + //parent.Children.AddChild(child); + + sess.Save(parent); + + var doctor = new Doctor {DoctorNumber = 123, MedicalRecord = parent.MedicalRecord}; + + sess.Save(doctor); + tx.Commit(); + + parentId = parent.Id; + doctorId = doctor.Id; + } + } + + [Test] + public void Test() + { + Log.Debug("Entering test"); + + using (ISession sess = OpenSession()) + { + Log.Debug("Loading doctor"); + var doctor = sess.Get<Doctor>(doctorId); // creates a proxy of the medical record + + Log.Debug("Loading parent"); + var parent = sess.Get<Parent>(parentId); + + Log.Debug("Adding new child to parent"); + parent.Children.AddChild(new Child { Age = 10, Parent = parent }); // does NOT cause Child.GetHashCode() to be called + + using (ITransaction tx = sess.BeginTransaction(IsolationLevel.ReadCommitted)) + { + Log.Debug("Saving parent"); + sess.Update(parent); + + Log.Debug("Committing transaction"); + tx.Commit(); // triggers Child.GetHashCode() to be called in flush machiney, leading to CNPBF exception + } + } + + Log.Debug("Exiting test"); + } + + protected override void OnTearDown() + { + using (ISession sess = OpenSession()) + using (ITransaction tx = sess.BeginTransaction()) + { + sess.Delete("from Doctor"); + sess.Delete("from Parent"); + sess.Delete("from Child"); + sess.Delete("from MedicalRecord"); + sess.Delete("from Disease"); + tx.Commit(); + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Mappings.hbm.xml 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate.Test.NHSpecificTest.NH1810" assembly="NHibernate.Test"> + + <class name="NHibernate.Test.NHSpecificTest.NH1810.Disease, NHibernate.Test" table="Disease" lazy="true"> + <cache usage="read-write" /> + <id name="Id" access="nosetter.camelcase" column="Id" type="Int32" unsaved-value="0"> + <generator class="native"> + </generator> + </id> + <property name="Name" access="property" type="String"> + <column name="Name"/> + </property> + <property name="Duration" access="property" type="Int32"> + <column name="Duration"/> + </property> + <many-to-one name="MedicalRecord" class="NHibernate.Test.NHSpecificTest.NH1810.MedicalRecord, NHibernate.Test" column="MedicalRecordId" lazy="proxy" cascade="none" /> + </class> + + <class name="NHibernate.Test.NHSpecificTest.NH1810.MedicalRecord, NHibernate.Test" table="MedicalRecord" lazy="true"> + <cache usage="read-write" /> + <id name="Id" access="nosetter.camelcase" column="Id" type="Int32" unsaved-value="0"> + <generator class="native"> + </generator> + </id> + <property name="Reference" access="property" type="String"> + <column name="Reference"/> + </property> + <set name="Diseases" access="nosetter.camelcase" table="Disease" lazy="true" inverse="true" cascade="all-delete-orphan"> + <key column="MedicalRecordId" /> + <one-to-many class="NHibernate.Test.NHSpecificTest.NH1810.Disease, NHibernate.Test" /> + </set> + </class> + + <class name="NHibernate.Test.NHSpecificTest.NH1810.Doctor, NHibernate.Test" table="Doctor" lazy="true"> + <cache usage="read-write" /> + <id name="Id" access="nosetter.camelcase" column="Id" type="Int32" unsaved-value="0"> + <generator class="native"> + </generator> + </id> + <property name="DoctorNumber" access="property" type="Int32"> + <column name="DoctorNumber"/> + </property> + <many-to-one name="MedicalRecord" class="NHibernate.Test.NHSpecificTest.NH1810.MedicalRecord, NHibernate.Test" column="MedicalRecordId" lazy="proxy" cascade="none" /> + </class> + + <class name="NHibernate.Test.NHSpecificTest.NH1810.Child, NHibernate.Test" table="Child" lazy="true"> + <cache usage="read-write" /> + <id name="Id" access="nosetter.camelcase" column="Id" type="Int32" unsaved-value="0"> + <generator class="native"> + </generator> + </id> + <property name="Age" access="property" type="Int32"> + <column name="Age"/> + </property> + <many-to-one name="Parent" class="NHibernate.Test.NHSpecificTest.NH1810.Parent, NHibernate.Test" column="ParentId" lazy="proxy" cascade="none" /> + </class> + + <class name="NHibernate.Test.NHSpecificTest.NH1810.Parent, NHibernate.Test" table="Parent" lazy="true"> + <cache usage="read-write" /> + <id name="Id" access="nosetter.camelcase" column="Id" type="Int32" unsaved-value="0"> + <generator class="native"> + </generator> + </id> + <property name="Address" access="property" type="String"> + <column name="Address"/> + </property> + <property name="Visits" access="property" type="Int32"> + <column name="Visits"/> + </property> + <set name="Children" access="nosetter.camelcase" table="Child" lazy="true" inverse="true" cascade="all-delete-orphan" collection-type="NHibernate.Test.NHSpecificTest.NH1810.Factory, NHibernate.Test"> + <key column="ParentId" /> + <one-to-many class="NHibernate.Test.NHSpecificTest.NH1810.Child, NHibernate.Test" /> + </set> + <many-to-one name="MedicalRecord" access="nosetter.camelcase" class="NHibernate.Test.NHSpecificTest.NH1810.MedicalRecord, NHibernate.Test" column="MedicalRecordId" lazy="proxy" cascade="all-delete-orphan" /> + </class> +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/MedicalRecord.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/MedicalRecord.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/MedicalRecord.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,57 @@ +using Iesi.Collections.Generic; +using log4net; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public class MedicalRecord + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int id; + ISet<Disease> diseases = new HashedSet<Disease>(); + string reference; + + public virtual int Id + { + get { return id; } + } + + public virtual ISet<Disease> Diseases + { + get { return diseases; } + } + + public virtual string Reference + { + get { return reference; } + set { reference = value; } + } + + public virtual bool Equals(MedicalRecord other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.Reference, Reference); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (MedicalRecord)) return false; + return Equals((MedicalRecord) obj); + } + + int? hashCode; + + public override int GetHashCode() + { + Log.Debug("MedicalRecord.GetHashCode()"); + + if (!hashCode.HasValue) + hashCode = (Reference != null ? Reference.GetHashCode() : 0); + + return hashCode.Value; + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Parent.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Parent.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1810/Parent.cs 2009-06-04 23:31:55 UTC (rev 4411) @@ -0,0 +1,76 @@ +using Iesi.Collections.Generic; +using log4net; + +namespace NHibernate.Test.NHSpecificTest.NH1810 +{ + public class Parent + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Fixture)); + + int id; + IChildren children = new Children(); + MedicalRecord medicalRecord = new MedicalRecord(); + string address; + int visits; + + public virtual int Id + { + get { return id; } + } + + public virtual IChildren Children + { + get { return children; } + } + + public virtual MedicalRecord MedicalRecord + { + get { return medicalRecord; } + } + + public virtual string Address + { + get { return address; } + set { address = value; } + } + + public virtual int Visits + { + get { return visits; } + set { visits = value; } + } + + public virtual bool Equals(Parent other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.MedicalRecord, MedicalRecord) && Equals(other.Address, Address) && other.Visits == Visits; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Parent)) return false; + return Equals((Parent) obj); + } + + int? hashCode; + + public override int GetHashCode() + { + Log.Debug("Parent.GetHashCode()"); + + if (!hashCode.HasValue) + unchecked + { + int result = (MedicalRecord != null ? MedicalRecord.GetHashCode() : 0); + result = (result*397) ^ (Address != null ? Address.GetHashCode() : 0); + result = (result*397) ^ Visits; + hashCode = result; + } + + return hashCode.Value; + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-06-04 19:16:07 UTC (rev 4410) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2009-06-04 23:31:55 UTC (rev 4411) @@ -472,6 +472,13 @@ <Compile Include="NHSpecificTest\NH1796\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1801\Domain.cs" /> <Compile Include="NHSpecificTest\NH1801\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1810\Child.cs" /> + <Compile Include="NHSpecificTest\NH1810\Children.cs" /> + <Compile Include="NHSpecificTest\NH1810\Disease.cs" /> + <Compile Include="NHSpecificTest\NH1810\Doctor.cs" /> + <Compile Include="NHSpecificTest\NH1810\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1810\MedicalRecord.cs" /> + <Compile Include="NHSpecificTest\NH1810\Parent.cs" /> <Compile Include="NHSpecificTest\NH645\HQLFunctionFixture.cs" /> <Compile Include="HQL\HQLFunctions.cs" /> <Compile Include="HQL\Human.cs" /> @@ -1867,6 +1874,7 @@ <EmbeddedResource Include="CacheTest\EntityWithFilters.xml" /> <EmbeddedResource Include="Classic\EntityWithLifecycle.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1810\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1092\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1507\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1044\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |