diff --git a/src/NHibernate.Test/NHSpecificTest/NH3487/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3487/Entity.cs new file mode 100644 index 00000000000..c15b7a5e3ec --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3487/Entity.cs @@ -0,0 +1,49 @@ +using System; +using Iesi.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH3487 +{ + [Serializable()] + public class Entity + { + public virtual Key Id { get; set; } + public virtual string Name { get; set; } + + public override bool Equals(object obj) + { + if(obj is Entity) + { + var otherEntity = (Entity)obj; + return otherEntity.Id.Equals(this.Id); + } + return false; + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } + } + + [Serializable()] + public class Key + { + public virtual int Id { get; set; } + + public override bool Equals(object obj) + { + if (obj is Key) + { + var otherEntity = (Key)obj; + return otherEntity.Id == this.Id; + } + return false; + } + + public override int GetHashCode() + { + // Important to reproduce the problem - forces the keys to collide in the hash map + return 1; + } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3487/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3487/Fixture.cs new file mode 100644 index 00000000000..13fb8a4283b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3487/Fixture.cs @@ -0,0 +1,88 @@ +using System; +using System.Linq; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using NHibernate.Linq; +using NHibernate.Collection; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3487 +{ + [TestFixture] + public class Fixture : BugTestCase + { + private Key key1; + private Key key2; + + public override string BugNumber + { + get { return "NH3487"; } + } + + protected override void OnSetUp() + { + using (ISession session = OpenSession()) + { + using (ITransaction transaction = session.BeginTransaction()) + { + key1 = new Key() { Id = 1 }; + var entity1 = new Entity { Id = key1, Name = "Bob1" }; + session.Save(entity1); + + key2 = new Key() { Id = 2 }; + var entity2 = new Entity { Id = key2, Name = "Bob2" }; + session.Save(entity2); + + session.Flush(); + transaction.Commit(); + } + } + } + + protected override void OnTearDown() + { + using (ISession session = OpenSession()) + { + using (ITransaction transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + } + + [Test] + public void Test() + { + IFormatter formatter = new BinaryFormatter(); + byte[] serializedSessionArray; + + using (ISession session = OpenSession()) + { + using (session.BeginTransaction()) + { + var entity1 = session.Get(key1); + var entity2 = session.Get(key2); + } + + session.Disconnect(); + using (var serializationStream = new MemoryStream()) + { + formatter.Serialize(serializationStream, session); + serializationStream.Close(); + serializedSessionArray = serializationStream.ToArray(); + } + } + + ISession deserializedSession; + using (var serializationStream = new MemoryStream(serializedSessionArray)) + { + deserializedSession = (ISession)formatter.Deserialize(serializationStream); + } + + } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3487/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH3487/Mappings.hbm.xml new file mode 100644 index 00000000000..82b63bfd708 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3487/Mappings.hbm.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index e2b5aec8ca2..22c7ad02ca3 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -672,6 +672,8 @@ + + @@ -2962,6 +2964,7 @@ + Designer diff --git a/src/NHibernate/Tuple/EntityModeToTuplizerMapping.cs b/src/NHibernate/Tuple/EntityModeToTuplizerMapping.cs index dbe7c2cd776..318c0bda2e1 100644 --- a/src/NHibernate/Tuple/EntityModeToTuplizerMapping.cs +++ b/src/NHibernate/Tuple/EntityModeToTuplizerMapping.cs @@ -1,19 +1,29 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using NHibernate.Util; namespace NHibernate.Tuple { /// Centralizes handling of to mappings. [Serializable] - public abstract class EntityModeToTuplizerMapping + public abstract class EntityModeToTuplizerMapping : IDeserializationCallback { + // NH-1660 private readonly IDictionary tuplizers = new LinkedHashMap(5, new EntityModeEqualityComparer()); + [NonSerialized()] + private bool isFullyDeserialized = false; + + public EntityModeToTuplizerMapping() + { + isFullyDeserialized = true; + } protected internal void AddTuplizer(EntityMode entityMode, ITuplizer tuplizer) { + EnsureFullyDeserialized(); tuplizers[entityMode] = tuplizer; } @@ -22,6 +32,7 @@ protected internal void AddTuplizer(EntityMode entityMode, ITuplizer tuplizer) /// The guessed entity mode. public virtual EntityMode? GuessEntityMode(object obj) { + EnsureFullyDeserialized(); foreach (KeyValuePair entry in tuplizers) { ITuplizer tuplizer = entry.Value; @@ -41,6 +52,7 @@ protected internal void AddTuplizer(EntityMode entityMode, ITuplizer tuplizer) /// The tuplizer, or null if not found. public virtual ITuplizer GetTuplizerOrNull(EntityMode entityMode) { + EnsureFullyDeserialized(); ITuplizer result; tuplizers.TryGetValue(entityMode, out result); return result; @@ -65,5 +77,19 @@ public virtual ITuplizer GetTuplizer(EntityMode entityMode) } return tuplizer; } + + private void EnsureFullyDeserialized() + { + if (!isFullyDeserialized) + { + ((IDeserializationCallback)this).OnDeserialization(this); + } + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + ((IDeserializationCallback)tuplizers).OnDeserialization(sender); + isFullyDeserialized = true; + } } } diff --git a/src/NHibernate/Util/LinkedHashMap.cs b/src/NHibernate/Util/LinkedHashMap.cs index 5606f9e26d8..fc4c9330995 100644 --- a/src/NHibernate/Util/LinkedHashMap.cs +++ b/src/NHibernate/Util/LinkedHashMap.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.Serialization; using System.Text; using NHibernate.DebugHelpers; @@ -18,7 +19,7 @@ namespace NHibernate.Util /// [DebuggerTypeProxy(typeof(CollectionProxy<>))] [Serializable] - public class LinkedHashMap : IDictionary + public class LinkedHashMap : IDictionary, IDeserializationCallback { [Serializable] protected class Entry @@ -359,6 +360,11 @@ private bool RemoveImpl(TKey key) return result; } + void IDeserializationCallback.OnDeserialization(object sender) + { + ((IDeserializationCallback)entries).OnDeserialization(sender); + } + #region System.Object Members public override string ToString()