From 278c5d3dddacb48a54d7d4208ca95b8d0e30ac04 Mon Sep 17 00:00:00 2001 From: maca88 Date: Tue, 26 Jun 2018 21:48:47 +0200 Subject: [PATCH 1/3] Make cache types serialization friendly --- .../Async/CacheTest/SerializationFixture.cs | 424 ++++++++++++++++++ .../CacheTest/SerializationFixture.cs | 414 +++++++++++++++++ .../Action/CollectionUpdateAction.cs | 4 +- src/NHibernate/Action/EntityInsertAction.cs | 2 +- src/NHibernate/Action/EntityUpdateAction.cs | 2 +- .../Async/Action/CollectionUpdateAction.cs | 2 +- .../Async/Action/EntityInsertAction.cs | 2 +- .../Async/Action/EntityUpdateAction.cs | 2 +- .../Async/Cache/Entry/CacheEntry.cs | 24 +- .../Async/Cache/Entry/CollectionCacheEntry.cs | 16 +- src/NHibernate/Async/Cache/ReadWriteCache.cs | 10 +- .../Engine/Loading/CollectionLoadContext.cs | 2 +- src/NHibernate/Async/Engine/TwoPhaseLoad.cs | 2 +- src/NHibernate/Async/Type/AnyType.cs | 27 +- src/NHibernate/Cache/CacheLock.cs | 105 +++-- src/NHibernate/Cache/CachedItem.cs | 67 ++- src/NHibernate/Cache/Entry/CacheEntry.cs | 84 ++-- .../Cache/Entry/CollectionCacheEntry.cs | 53 ++- .../Cache/Entry/StructuredCacheEntry.cs | 8 +- .../Entry/StructuredCollectionCacheEntry.cs | 4 +- .../Cache/Entry/StructuredMapCacheEntry.cs | 4 +- src/NHibernate/Cache/ReadWriteCache.cs | 10 +- .../Engine/Loading/CollectionLoadContext.cs | 2 +- src/NHibernate/Engine/TwoPhaseLoad.cs | 2 +- src/NHibernate/Type/AnyType.cs | 45 +- 25 files changed, 1191 insertions(+), 126 deletions(-) create mode 100644 src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs create mode 100644 src/NHibernate.Test/CacheTest/SerializationFixture.cs diff --git a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs new file mode 100644 index 00000000000..5890c7cceaa --- /dev/null +++ b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs @@ -0,0 +1,424 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Serialization; +using NHibernate.Cache; +using NHibernate.Cache.Entry; +using NHibernate.Engine; +using NHibernate.Intercept; +using NHibernate.Persister.Entity; +using NHibernate.Properties; +using NHibernate.Type; +using NSubstitute; +using NUnit.Framework; + +namespace NHibernate.Test.CacheTest +{ + [TestFixture] + public class SerializationFixtureAsync + { + // XmlSerializer does not support DateTimeOffset and TimeSpan types + private readonly Func, bool> _xmlSerializerTypePredicate = + o => !(o.Value is DateTimeOffset) && !(o.Value is TimeSpan); + + [Test] + public async Task TestCacheEntrySerializationAsync() + { + var item = CreateCacheEntry(null); + var copy = await (TestDataContractSerializerAsync(item)); + CheckCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckCacheEntry(item, copy); + + item = CreateCacheEntry(_xmlSerializerTypePredicate); + copy = TestXmlSerializer(item); + CheckCacheEntry(item, copy); + } + + [Test] + public async Task TestCollectionCacheEntrySerializationAsync() + { + var item = CreateCollectionCacheEntry(null); + var copy = await (TestDataContractSerializerAsync(item)); + CheckCollectionCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckCollectionCacheEntry(item, copy); + + item = CreateCollectionCacheEntry(_xmlSerializerTypePredicate); + copy = TestXmlSerializer(item); + CheckCollectionCacheEntry(item, copy); + } + + [Test] + public async Task TestCachedItemSerializationAsync() + { + // CacheEntry + var item = CreateCachedItem(CreateCacheEntry(null)); + var copy = await (TestDataContractSerializerAsync(item)); + CheckCachedItem(item, copy); + + copy = TestBinaryFormatter(item); + CheckCachedItem(item, copy); + + item = CreateCachedItem(CreateCacheEntry(_xmlSerializerTypePredicate)); + copy = TestXmlSerializer(item); + CheckCachedItem(item, copy); + + // CollectionCacheEntry + item = CreateCachedItem(CreateCollectionCacheEntry(null)); + copy = await (TestDataContractSerializerAsync(item)); + CheckCachedItem(item, copy); + + copy = TestBinaryFormatter(item); + CheckCachedItem(item, copy); + + item = CreateCachedItem(CreateCollectionCacheEntry(_xmlSerializerTypePredicate)); + copy = TestXmlSerializer(item); + CheckCachedItem(item, copy); + } + + [Test] + public async Task TestCacheLockSerializationAsync() + { + var item = new CacheLock + { + Version = 3.5m, + Id = 100, + Timeout = 999, + UnlockTimestamp = 444, + Multiplicity = 5, + WasLockedConcurrently = false + }; + var copy = await (TestDataContractSerializerAsync(item)); + CheckCacheLock(item, copy); + + copy = TestBinaryFormatter(item); + CheckCacheLock(item, copy); + + copy = TestXmlSerializer(item); + CheckCacheLock(item, copy); + } + + [Test] + public async Task TestAnyTypeObjectTypeCacheEntrySerializationAsync() + { + var item = CreateObjectTypeCacheEntry(); + var copy = await (TestDataContractSerializerAsync(item)); + CheckObjectTypeCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckObjectTypeCacheEntry(item, copy); + + copy = TestXmlSerializer(item); + CheckObjectTypeCacheEntry(item, copy); + } + + + [Serializable] + public class MyEntity + { + public int Id { get; set; } + } + + private CachedItem CreateCachedItem(object value) + { + return new CachedItem + { + Version = 55L, + Value = value, + FreshTimestamp = 500 + }; + } + + private CacheEntry CreateCacheEntry(Func, bool> predicate) + { + return new CacheEntry + { + DisassembledState = GetAllKnownTypeValues(predicate), + Version = 55, + Subclass = "Test", + AreLazyPropertiesUnfetched = true + }; + } + + private CollectionCacheEntry CreateCollectionCacheEntry(Func, bool> predicate) + { + return new CollectionCacheEntry + { + DisassembledState = GetAllKnownTypeValues(predicate) + }; + } + + private object[] GetAllKnownTypeValues(Func, bool> predicate) + { + var entityName = nameof(MyEntity); + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml("XmlDoc"); + var types = new Dictionary + { + {NHibernateUtil.AnsiString, "test"}, + {NHibernateUtil.Binary, new byte[] {1, 2, 3, 4}}, + {NHibernateUtil.BinaryBlob, new byte[] {1, 2, 3, 4}}, + {NHibernateUtil.Boolean, true}, + {NHibernateUtil.Byte, (byte) 1}, + {NHibernateUtil.Character, 'a'}, + {NHibernateUtil.CultureInfo, CultureInfo.CurrentCulture}, + {NHibernateUtil.DateTime, DateTime.Now}, + {NHibernateUtil.DateTimeNoMs, DateTime.Now}, + {NHibernateUtil.LocalDateTime, DateTime.Now}, + {NHibernateUtil.UtcDateTime, DateTime.UtcNow}, + {NHibernateUtil.LocalDateTimeNoMs, DateTime.Now}, + {NHibernateUtil.UtcDateTimeNoMs, DateTime.UtcNow}, + {NHibernateUtil.DateTimeOffset, DateTimeOffset.Now}, + {NHibernateUtil.Date, DateTime.Today}, + {NHibernateUtil.Decimal, 2.5m}, + {NHibernateUtil.Double, 2.5d}, + {NHibernateUtil.Currency, 2.5m}, + {NHibernateUtil.Guid, Guid.NewGuid()}, + {NHibernateUtil.Int16, (short) 1}, + {NHibernateUtil.Int32, 3}, + {NHibernateUtil.Int64, 3L}, + {NHibernateUtil.SByte, (sbyte) 1}, + {NHibernateUtil.UInt16, (ushort) 1}, + {NHibernateUtil.UInt32, (uint) 1}, + {NHibernateUtil.UInt64, (ulong) 1}, + {NHibernateUtil.Single, 1.1f}, + {NHibernateUtil.String, "test"}, + {NHibernateUtil.StringClob, "test"}, + {NHibernateUtil.Time, DateTime.Now}, + {NHibernateUtil.Ticks, DateTime.Now}, + {NHibernateUtil.TimeAsTimeSpan, TimeSpan.FromMilliseconds(15)}, + {NHibernateUtil.TimeSpan, TimeSpan.FromMilliseconds(1234)}, + {NHibernateUtil.DbTimestamp, DateTime.Now}, + {NHibernateUtil.TrueFalse, false}, + {NHibernateUtil.YesNo, true}, + {NHibernateUtil.Class, typeof(IType)}, + {NHibernateUtil.ClassMetaType, entityName}, + {NHibernateUtil.Serializable, new MyEntity {Id = 1}}, + {NHibernateUtil.Object, new MyEntity {Id = 10}}, + {NHibernateUtil.AnsiChar, 'a'}, + {NHibernateUtil.XmlDoc, xmlDoc}, + {NHibernateUtil.XDoc, XDocument.Parse("XDoc")}, + {NHibernateUtil.Uri, new Uri("http://test.com")} + }; + if (predicate != null) + { + types = types.Where(predicate).ToDictionary(o => o.Key, o => o.Value); + } + + var sessionImpl = Substitute.For(); + sessionImpl.BestGuessEntityName(Arg.Any()).Returns(o => o[0].GetType().Name); + sessionImpl.GetContextEntityIdentifier(Arg.Is(o => o is MyEntity)).Returns(o => ((MyEntity) o[0]).Id); + return TypeHelper.Disassemble( + types.Values.ToArray(), + types.Keys.Cast().ToArray(), + null, + sessionImpl, + null) + .Concat( + new[] + { + LazyPropertyInitializer.UnfetchedProperty, + BackrefPropertyAccessor.Unknown + }) + .ToArray(); + } + + private AnyType.ObjectTypeCacheEntry CreateObjectTypeCacheEntry() + { + return new AnyType.ObjectTypeCacheEntry + { + Id = 100, + EntityName = "Test" + }; + } + + private void CheckCacheEntry(CacheEntry original, CacheEntry copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Subclass, Is.EqualTo(original.Subclass)); + Assert.That(copy.AreLazyPropertiesUnfetched, Is.EqualTo(original.AreLazyPropertiesUnfetched)); + for (var i = 0; i < copy.DisassembledState.Length; i++) + { + Assert.That(copy.DisassembledState[i], Is.TypeOf(original.DisassembledState[i].GetType())); + if (original.DisassembledState[i] is AnyType.ObjectTypeCacheEntry originalAnyType) + { + var copyAnyType = (AnyType.ObjectTypeCacheEntry) copy.DisassembledState[i]; + CheckObjectTypeCacheEntry(originalAnyType, copyAnyType); + } + else + { + Assert.That(copy.DisassembledState[i], Is.EqualTo(original.DisassembledState[i])); + } + } + } + + private void CheckCachedItem(CachedItem original, CachedItem copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Value, Is.TypeOf(original.Value.GetType())); + switch (original.Value) + { + case CacheEntry cacheEntry: + CheckCacheEntry(cacheEntry, (CacheEntry) copy.Value); + break; + case CollectionCacheEntry colleectionCacheEntry: + CheckCollectionCacheEntry(colleectionCacheEntry, (CollectionCacheEntry) copy.Value); + break; + default: + Assert.That(copy.Value, Is.EqualTo(original.Value)); + break; + } + Assert.That(copy.FreshTimestamp, Is.EqualTo(original.FreshTimestamp)); + } + + private void CheckCollectionCacheEntry(CollectionCacheEntry original, CollectionCacheEntry copy) + { + Assert.That(copy.DisassembledState, Is.TypeOf(original.DisassembledState.GetType())); + + var originalArray = (object[]) original.DisassembledState; + var copyArray = (object[]) copy.DisassembledState; + + for (var i = 0; i < copyArray.Length; i++) + { + Assert.That(copyArray[i], Is.TypeOf(originalArray[i].GetType())); + if (originalArray[i] is AnyType.ObjectTypeCacheEntry originalAnyType) + { + var copyAnyType = (AnyType.ObjectTypeCacheEntry) copyArray[i]; + CheckObjectTypeCacheEntry(originalAnyType, copyAnyType); + } + else + { + Assert.That(copyArray[i], Is.EqualTo(originalArray[i])); + } + } + } + + private void CheckCacheLock(CacheLock original, CacheLock copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Id, Is.EqualTo(original.Id)); + Assert.That(copy.Multiplicity, Is.EqualTo(original.Multiplicity)); + Assert.That(copy.Timeout, Is.EqualTo(original.Timeout)); + Assert.That(copy.UnlockTimestamp, Is.EqualTo(original.UnlockTimestamp)); + Assert.That(copy.WasLockedConcurrently, Is.EqualTo(original.WasLockedConcurrently)); + } + + private void CheckObjectTypeCacheEntry(AnyType.ObjectTypeCacheEntry original, AnyType.ObjectTypeCacheEntry copy) + { + Assert.That(copy.Id, Is.EqualTo(original.Id)); + Assert.That(copy.EntityName, Is.EqualTo(original.EntityName)); + } + + private static async Task TestDataContractSerializerAsync(T obj) + { + var xml = await (DataContractSerializerToXmlAsync(obj)); + obj = DataContractSerializerFromXml(xml); + Assert.That(xml, Is.EqualTo(await (DataContractSerializerToXmlAsync(obj)))); + return obj; + } + + private static T TestXmlSerializer(T obj) + { + var xml = XmlSerializerToXml(obj); + obj = XmlSerializerFromXml(xml); + Assert.That(xml, Is.EqualTo(XmlSerializerToXml(obj))); + return obj; + } + + private static T TestBinaryFormatter(T obj) + { + var bytes = BinaryFormatterToBinary(obj); + obj = BinaryFormatterFromBinary(bytes); + Assert.That(bytes, Is.EqualTo(BinaryFormatterToBinary(obj))); + return obj; + } + + private static async Task DataContractSerializerToXmlAsync(T obj) + { + using (var memoryStream = new MemoryStream()) + using (var reader = new StreamReader(memoryStream)) + { + + var serializer = new DataContractSerializer(typeof(T)); + serializer.WriteObject(memoryStream, obj); + memoryStream.Position = 0; + return await (reader.ReadToEndAsync()); + } + } + + private static T DataContractSerializerFromXml(string xml) + { + using (var stream = new MemoryStream()) + { + var data = Encoding.UTF8.GetBytes(xml); + stream.Write(data, 0, data.Length); + stream.Position = 0; + var deserializer = new DataContractSerializer(typeof(T)); + return (T) deserializer.ReadObject(stream); + } + } + + private static string XmlSerializerToXml(T obj) + { + var serializer = new XmlSerializer(typeof(T)); + using (var writer = new StringWriter()) + { + serializer.Serialize(writer, obj); + return writer.ToString(); + } + } + + private static T XmlSerializerFromXml(string xml) + { + var serializer = new XmlSerializer(typeof(T)); + using (var reader = new StringReader(xml)) + { + return (T) serializer.Deserialize(reader); + } + } + + private static byte[] BinaryFormatterToBinary(T obj) + { + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, obj); + return stream.ToArray(); + } + } + + private static T BinaryFormatterFromBinary(byte[] value) + { + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream(value)) + { + return (T)serializer.Deserialize(stream); + } + } + } +} diff --git a/src/NHibernate.Test/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/CacheTest/SerializationFixture.cs new file mode 100644 index 00000000000..7aa98db5a7e --- /dev/null +++ b/src/NHibernate.Test/CacheTest/SerializationFixture.cs @@ -0,0 +1,414 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.Serialization; +using NHibernate.Cache; +using NHibernate.Cache.Entry; +using NHibernate.Engine; +using NHibernate.Intercept; +using NHibernate.Persister.Entity; +using NHibernate.Properties; +using NHibernate.Type; +using NSubstitute; +using NUnit.Framework; + +namespace NHibernate.Test.CacheTest +{ + [TestFixture] + public class SerializationFixture + { + // XmlSerializer does not support DateTimeOffset and TimeSpan types + private readonly Func, bool> _xmlSerializerTypePredicate = + o => !(o.Value is DateTimeOffset) && !(o.Value is TimeSpan); + + [Test] + public void TestCacheEntrySerialization() + { + var item = CreateCacheEntry(null); + var copy = TestDataContractSerializer(item); + CheckCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckCacheEntry(item, copy); + + item = CreateCacheEntry(_xmlSerializerTypePredicate); + copy = TestXmlSerializer(item); + CheckCacheEntry(item, copy); + } + + [Test] + public void TestCollectionCacheEntrySerialization() + { + var item = CreateCollectionCacheEntry(null); + var copy = TestDataContractSerializer(item); + CheckCollectionCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckCollectionCacheEntry(item, copy); + + item = CreateCollectionCacheEntry(_xmlSerializerTypePredicate); + copy = TestXmlSerializer(item); + CheckCollectionCacheEntry(item, copy); + } + + [Test] + public void TestCachedItemSerialization() + { + // CacheEntry + var item = CreateCachedItem(CreateCacheEntry(null)); + var copy = TestDataContractSerializer(item); + CheckCachedItem(item, copy); + + copy = TestBinaryFormatter(item); + CheckCachedItem(item, copy); + + item = CreateCachedItem(CreateCacheEntry(_xmlSerializerTypePredicate)); + copy = TestXmlSerializer(item); + CheckCachedItem(item, copy); + + // CollectionCacheEntry + item = CreateCachedItem(CreateCollectionCacheEntry(null)); + copy = TestDataContractSerializer(item); + CheckCachedItem(item, copy); + + copy = TestBinaryFormatter(item); + CheckCachedItem(item, copy); + + item = CreateCachedItem(CreateCollectionCacheEntry(_xmlSerializerTypePredicate)); + copy = TestXmlSerializer(item); + CheckCachedItem(item, copy); + } + + [Test] + public void TestCacheLockSerialization() + { + var item = new CacheLock + { + Version = 3.5m, + Id = 100, + Timeout = 999, + UnlockTimestamp = 444, + Multiplicity = 5, + WasLockedConcurrently = false + }; + var copy = TestDataContractSerializer(item); + CheckCacheLock(item, copy); + + copy = TestBinaryFormatter(item); + CheckCacheLock(item, copy); + + copy = TestXmlSerializer(item); + CheckCacheLock(item, copy); + } + + [Test] + public void TestAnyTypeObjectTypeCacheEntrySerialization() + { + var item = CreateObjectTypeCacheEntry(); + var copy = TestDataContractSerializer(item); + CheckObjectTypeCacheEntry(item, copy); + + copy = TestBinaryFormatter(item); + CheckObjectTypeCacheEntry(item, copy); + + copy = TestXmlSerializer(item); + CheckObjectTypeCacheEntry(item, copy); + } + + + [Serializable] + public class MyEntity + { + public int Id { get; set; } + } + + private CachedItem CreateCachedItem(object value) + { + return new CachedItem + { + Version = 55L, + Value = value, + FreshTimestamp = 500 + }; + } + + private CacheEntry CreateCacheEntry(Func, bool> predicate) + { + return new CacheEntry + { + DisassembledState = GetAllKnownTypeValues(predicate), + Version = 55, + Subclass = "Test", + AreLazyPropertiesUnfetched = true + }; + } + + private CollectionCacheEntry CreateCollectionCacheEntry(Func, bool> predicate) + { + return new CollectionCacheEntry + { + DisassembledState = GetAllKnownTypeValues(predicate) + }; + } + + private object[] GetAllKnownTypeValues(Func, bool> predicate) + { + var entityName = nameof(MyEntity); + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml("XmlDoc"); + var types = new Dictionary + { + {NHibernateUtil.AnsiString, "test"}, + {NHibernateUtil.Binary, new byte[] {1, 2, 3, 4}}, + {NHibernateUtil.BinaryBlob, new byte[] {1, 2, 3, 4}}, + {NHibernateUtil.Boolean, true}, + {NHibernateUtil.Byte, (byte) 1}, + {NHibernateUtil.Character, 'a'}, + {NHibernateUtil.CultureInfo, CultureInfo.CurrentCulture}, + {NHibernateUtil.DateTime, DateTime.Now}, + {NHibernateUtil.DateTimeNoMs, DateTime.Now}, + {NHibernateUtil.LocalDateTime, DateTime.Now}, + {NHibernateUtil.UtcDateTime, DateTime.UtcNow}, + {NHibernateUtil.LocalDateTimeNoMs, DateTime.Now}, + {NHibernateUtil.UtcDateTimeNoMs, DateTime.UtcNow}, + {NHibernateUtil.DateTimeOffset, DateTimeOffset.Now}, + {NHibernateUtil.Date, DateTime.Today}, + {NHibernateUtil.Decimal, 2.5m}, + {NHibernateUtil.Double, 2.5d}, + {NHibernateUtil.Currency, 2.5m}, + {NHibernateUtil.Guid, Guid.NewGuid()}, + {NHibernateUtil.Int16, (short) 1}, + {NHibernateUtil.Int32, 3}, + {NHibernateUtil.Int64, 3L}, + {NHibernateUtil.SByte, (sbyte) 1}, + {NHibernateUtil.UInt16, (ushort) 1}, + {NHibernateUtil.UInt32, (uint) 1}, + {NHibernateUtil.UInt64, (ulong) 1}, + {NHibernateUtil.Single, 1.1f}, + {NHibernateUtil.String, "test"}, + {NHibernateUtil.StringClob, "test"}, + {NHibernateUtil.Time, DateTime.Now}, + {NHibernateUtil.Ticks, DateTime.Now}, + {NHibernateUtil.TimeAsTimeSpan, TimeSpan.FromMilliseconds(15)}, + {NHibernateUtil.TimeSpan, TimeSpan.FromMilliseconds(1234)}, + {NHibernateUtil.DbTimestamp, DateTime.Now}, + {NHibernateUtil.TrueFalse, false}, + {NHibernateUtil.YesNo, true}, + {NHibernateUtil.Class, typeof(IType)}, + {NHibernateUtil.ClassMetaType, entityName}, + {NHibernateUtil.Serializable, new MyEntity {Id = 1}}, + {NHibernateUtil.Object, new MyEntity {Id = 10}}, + {NHibernateUtil.AnsiChar, 'a'}, + {NHibernateUtil.XmlDoc, xmlDoc}, + {NHibernateUtil.XDoc, XDocument.Parse("XDoc")}, + {NHibernateUtil.Uri, new Uri("http://test.com")} + }; + if (predicate != null) + { + types = types.Where(predicate).ToDictionary(o => o.Key, o => o.Value); + } + + var sessionImpl = Substitute.For(); + sessionImpl.BestGuessEntityName(Arg.Any()).Returns(o => o[0].GetType().Name); + sessionImpl.GetContextEntityIdentifier(Arg.Is(o => o is MyEntity)).Returns(o => ((MyEntity) o[0]).Id); + return TypeHelper.Disassemble( + types.Values.ToArray(), + types.Keys.Cast().ToArray(), + null, + sessionImpl, + null) + .Concat( + new[] + { + LazyPropertyInitializer.UnfetchedProperty, + BackrefPropertyAccessor.Unknown + }) + .ToArray(); + } + + private AnyType.ObjectTypeCacheEntry CreateObjectTypeCacheEntry() + { + return new AnyType.ObjectTypeCacheEntry + { + Id = 100, + EntityName = "Test" + }; + } + + private void CheckCacheEntry(CacheEntry original, CacheEntry copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Subclass, Is.EqualTo(original.Subclass)); + Assert.That(copy.AreLazyPropertiesUnfetched, Is.EqualTo(original.AreLazyPropertiesUnfetched)); + for (var i = 0; i < copy.DisassembledState.Length; i++) + { + Assert.That(copy.DisassembledState[i], Is.TypeOf(original.DisassembledState[i].GetType())); + if (original.DisassembledState[i] is AnyType.ObjectTypeCacheEntry originalAnyType) + { + var copyAnyType = (AnyType.ObjectTypeCacheEntry) copy.DisassembledState[i]; + CheckObjectTypeCacheEntry(originalAnyType, copyAnyType); + } + else + { + Assert.That(copy.DisassembledState[i], Is.EqualTo(original.DisassembledState[i])); + } + } + } + + private void CheckCachedItem(CachedItem original, CachedItem copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Value, Is.TypeOf(original.Value.GetType())); + switch (original.Value) + { + case CacheEntry cacheEntry: + CheckCacheEntry(cacheEntry, (CacheEntry) copy.Value); + break; + case CollectionCacheEntry colleectionCacheEntry: + CheckCollectionCacheEntry(colleectionCacheEntry, (CollectionCacheEntry) copy.Value); + break; + default: + Assert.That(copy.Value, Is.EqualTo(original.Value)); + break; + } + Assert.That(copy.FreshTimestamp, Is.EqualTo(original.FreshTimestamp)); + } + + private void CheckCollectionCacheEntry(CollectionCacheEntry original, CollectionCacheEntry copy) + { + Assert.That(copy.DisassembledState, Is.TypeOf(original.DisassembledState.GetType())); + + var originalArray = (object[]) original.DisassembledState; + var copyArray = (object[]) copy.DisassembledState; + + for (var i = 0; i < copyArray.Length; i++) + { + Assert.That(copyArray[i], Is.TypeOf(originalArray[i].GetType())); + if (originalArray[i] is AnyType.ObjectTypeCacheEntry originalAnyType) + { + var copyAnyType = (AnyType.ObjectTypeCacheEntry) copyArray[i]; + CheckObjectTypeCacheEntry(originalAnyType, copyAnyType); + } + else + { + Assert.That(copyArray[i], Is.EqualTo(originalArray[i])); + } + } + } + + private void CheckCacheLock(CacheLock original, CacheLock copy) + { + Assert.That(copy.Version, Is.EqualTo(original.Version)); + Assert.That(copy.Version, Is.TypeOf(original.Version.GetType())); + Assert.That(copy.Id, Is.EqualTo(original.Id)); + Assert.That(copy.Multiplicity, Is.EqualTo(original.Multiplicity)); + Assert.That(copy.Timeout, Is.EqualTo(original.Timeout)); + Assert.That(copy.UnlockTimestamp, Is.EqualTo(original.UnlockTimestamp)); + Assert.That(copy.WasLockedConcurrently, Is.EqualTo(original.WasLockedConcurrently)); + } + + private void CheckObjectTypeCacheEntry(AnyType.ObjectTypeCacheEntry original, AnyType.ObjectTypeCacheEntry copy) + { + Assert.That(copy.Id, Is.EqualTo(original.Id)); + Assert.That(copy.EntityName, Is.EqualTo(original.EntityName)); + } + + private static T TestDataContractSerializer(T obj) + { + var xml = DataContractSerializerToXml(obj); + obj = DataContractSerializerFromXml(xml); + Assert.That(xml, Is.EqualTo(DataContractSerializerToXml(obj))); + return obj; + } + + private static T TestXmlSerializer(T obj) + { + var xml = XmlSerializerToXml(obj); + obj = XmlSerializerFromXml(xml); + Assert.That(xml, Is.EqualTo(XmlSerializerToXml(obj))); + return obj; + } + + private static T TestBinaryFormatter(T obj) + { + var bytes = BinaryFormatterToBinary(obj); + obj = BinaryFormatterFromBinary(bytes); + Assert.That(bytes, Is.EqualTo(BinaryFormatterToBinary(obj))); + return obj; + } + + private static string DataContractSerializerToXml(T obj) + { + using (var memoryStream = new MemoryStream()) + using (var reader = new StreamReader(memoryStream)) + { + + var serializer = new DataContractSerializer(typeof(T)); + serializer.WriteObject(memoryStream, obj); + memoryStream.Position = 0; + return reader.ReadToEnd(); + } + } + + private static T DataContractSerializerFromXml(string xml) + { + using (var stream = new MemoryStream()) + { + var data = Encoding.UTF8.GetBytes(xml); + stream.Write(data, 0, data.Length); + stream.Position = 0; + var deserializer = new DataContractSerializer(typeof(T)); + return (T) deserializer.ReadObject(stream); + } + } + + private static string XmlSerializerToXml(T obj) + { + var serializer = new XmlSerializer(typeof(T)); + using (var writer = new StringWriter()) + { + serializer.Serialize(writer, obj); + return writer.ToString(); + } + } + + private static T XmlSerializerFromXml(string xml) + { + var serializer = new XmlSerializer(typeof(T)); + using (var reader = new StringReader(xml)) + { + return (T) serializer.Deserialize(reader); + } + } + + private static byte[] BinaryFormatterToBinary(T obj) + { + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream()) + { + serializer.Serialize(stream, obj); + return stream.ToArray(); + } + } + + private static T BinaryFormatterFromBinary(byte[] value) + { + var serializer = new BinaryFormatter(); + using (var stream = new MemoryStream(value)) + { + return (T)serializer.Deserialize(stream); + } + } + } +} diff --git a/src/NHibernate/Action/CollectionUpdateAction.cs b/src/NHibernate/Action/CollectionUpdateAction.cs index 7153105f704..f86c009e5d9 100644 --- a/src/NHibernate/Action/CollectionUpdateAction.cs +++ b/src/NHibernate/Action/CollectionUpdateAction.cs @@ -139,7 +139,7 @@ public override AfterTransactionCompletionProcessDelegate AfterTransactionComple // or detached from the session if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection)) { - CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister); + CollectionCacheEntry entry = CollectionCacheEntry.Create(Collection, Persister); bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock); if (put && Session.Factory.Statistics.IsStatisticsEnabled) @@ -158,4 +158,4 @@ public override AfterTransactionCompletionProcessDelegate AfterTransactionComple } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Action/EntityInsertAction.cs b/src/NHibernate/Action/EntityInsertAction.cs index c34ec0e615a..6f4f9a71a45 100644 --- a/src/NHibernate/Action/EntityInsertAction.cs +++ b/src/NHibernate/Action/EntityInsertAction.cs @@ -74,7 +74,7 @@ public override void Execute() if (IsCachePutEnabled(persister)) { - CacheEntry ce = new CacheEntry(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance); + CacheEntry ce = CacheEntry.Create(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance); cacheEntry = persister.CacheEntryStructure.Structure(ce); CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); diff --git a/src/NHibernate/Action/EntityUpdateAction.cs b/src/NHibernate/Action/EntityUpdateAction.cs index 68a92148f2d..dfac0d86120 100644 --- a/src/NHibernate/Action/EntityUpdateAction.cs +++ b/src/NHibernate/Action/EntityUpdateAction.cs @@ -114,7 +114,7 @@ public override void Execute() } else { - CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance), nextVersion, Session, instance); + CacheEntry ce = CacheEntry.Create(state, persister, persister.HasUninitializedLazyProperties(instance), nextVersion, Session, instance); cacheEntry = persister.CacheEntryStructure.Structure(ce); bool put = persister.Cache.Update(ck, cacheEntry, nextVersion, previousVersion); diff --git a/src/NHibernate/Async/Action/CollectionUpdateAction.cs b/src/NHibernate/Async/Action/CollectionUpdateAction.cs index 56fb853dc4b..8ca53b5bfa7 100644 --- a/src/NHibernate/Async/Action/CollectionUpdateAction.cs +++ b/src/NHibernate/Async/Action/CollectionUpdateAction.cs @@ -119,4 +119,4 @@ private async Task PostUpdateAsync(CancellationToken cancellationToken) } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Async/Action/EntityInsertAction.cs b/src/NHibernate/Async/Action/EntityInsertAction.cs index 29ae4d55a13..4a0115dc06a 100644 --- a/src/NHibernate/Async/Action/EntityInsertAction.cs +++ b/src/NHibernate/Async/Action/EntityInsertAction.cs @@ -70,7 +70,7 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken) if (IsCachePutEnabled(persister)) { - CacheEntry ce = new CacheEntry(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance); + CacheEntry ce = await (CacheEntry.CreateAsync(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance, cancellationToken)).ConfigureAwait(false); cacheEntry = persister.CacheEntryStructure.Structure(ce); CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); diff --git a/src/NHibernate/Async/Action/EntityUpdateAction.cs b/src/NHibernate/Async/Action/EntityUpdateAction.cs index 53a577aefb4..33f1cab8fdc 100644 --- a/src/NHibernate/Async/Action/EntityUpdateAction.cs +++ b/src/NHibernate/Async/Action/EntityUpdateAction.cs @@ -99,7 +99,7 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken) } else { - CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance), nextVersion, Session, instance); + CacheEntry ce = await (CacheEntry.CreateAsync(state, persister, persister.HasUninitializedLazyProperties(instance), nextVersion, Session, instance, cancellationToken)).ConfigureAwait(false); cacheEntry = persister.CacheEntryStructure.Structure(ce); bool put = await (persister.Cache.UpdateAsync(ck, cacheEntry, nextVersion, previousVersion, cancellationToken)).ConfigureAwait(false); diff --git a/src/NHibernate/Async/Cache/Entry/CacheEntry.cs b/src/NHibernate/Async/Cache/Entry/CacheEntry.cs index 68fcad94520..42201158558 100644 --- a/src/NHibernate/Async/Cache/Entry/CacheEntry.cs +++ b/src/NHibernate/Async/Cache/Entry/CacheEntry.cs @@ -9,9 +9,13 @@ using System; +using System.Runtime.Serialization; +using System.Xml.Serialization; using NHibernate.Engine; using NHibernate.Event; +using NHibernate.Intercept; using NHibernate.Persister.Entity; +using NHibernate.Properties; using NHibernate.Type; namespace NHibernate.Cache.Entry @@ -21,10 +25,24 @@ namespace NHibernate.Cache.Entry public sealed partial class CacheEntry { + public static async Task CreateAsync(object[] state, IEntityPersister persister, bool unfetched, object version, + ISessionImplementor session, object owner, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + return new CacheEntry + { + //disassembled state gets put in a new array (we write to cache by value!) + DisassembledState = await (TypeHelper.DisassembleAsync(state, persister.PropertyTypes, null, session, owner, cancellationToken)).ConfigureAwait(false), + AreLazyPropertiesUnfetched = unfetched || !persister.IsLazyPropertiesCacheable, + Subclass = persister.EntityName, + Version = version + }; + } + public Task AssembleAsync(object instance, object id, IEntityPersister persister, IInterceptor interceptor, ISessionImplementor session, CancellationToken cancellationToken) { - if (!persister.EntityName.Equals(subclass)) + if (!persister.EntityName.Equals(Subclass)) { throw new AssertionFailure("Tried to assemble a different subclass instance"); } @@ -33,7 +51,7 @@ public Task AssembleAsync(object instance, object id, IEntityPersister return Task.FromCanceled(cancellationToken); } - return AssembleAsync(disassembledState, instance, id, persister, interceptor, session, cancellationToken); + return AssembleAsync(DisassembledState, instance, id, persister, interceptor, session, cancellationToken); } private static async Task AssembleAsync(object[] values, object result, object id, IEntityPersister persister, @@ -61,4 +79,4 @@ private static async Task AssembleAsync(object[] values, object result return assembledProps; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs index f82139126fe..7a553c37ab3 100644 --- a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs @@ -9,8 +9,13 @@ using System; +using System.Runtime.Serialization; +using System.Xml.Serialization; using NHibernate.Collection; +using NHibernate.Intercept; using NHibernate.Persister.Collection; +using NHibernate.Properties; +using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Cache.Entry @@ -20,10 +25,19 @@ namespace NHibernate.Cache.Entry public partial class CollectionCacheEntry { + public static async Task CreateAsync(IPersistentCollection collection, ICollectionPersister persister, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + return new CollectionCacheEntry + { + DisassembledState = await (collection.DisassembleAsync(persister, cancellationToken)).ConfigureAwait(false) + }; + } + public virtual async Task AssembleAsync(IPersistentCollection collection, ICollectionPersister persister, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - await (collection.InitializeFromCacheAsync(persister, state, owner, cancellationToken)).ConfigureAwait(false); + await (collection.InitializeFromCacheAsync(persister, DisassembledState, owner, cancellationToken)).ConfigureAwait(false); collection.AfterInitialize(persister); } } diff --git a/src/NHibernate/Async/Cache/ReadWriteCache.cs b/src/NHibernate/Async/Cache/ReadWriteCache.cs index 217ac12cada..b0433287b59 100644 --- a/src/NHibernate/Async/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Async/Cache/ReadWriteCache.cs @@ -112,7 +112,7 @@ public async Task LockAsync(CacheKey key, object version, Cancellatio ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); long timeout = cache.NextTimestamp() + cache.Timeout; CacheLock @lock = lockable == null ? - new CacheLock(timeout, NextLockId(), version) : + CacheLock.Create(timeout, NextLockId(), version) : lockable.Lock(timeout, NextLockId()); await (cache.PutAsync(key, @lock, cancellationToken)).ConfigureAwait(false); return @lock; @@ -159,7 +159,7 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o if (puttable) { - await (cache.PutAsync(key, new CachedItem(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -252,7 +252,7 @@ internal Task HandleLockExpiryAsync(object key, CancellationToken cancellationTo log.Warn("An item was expired by the cache while it was locked (increase your cache timeout): {0}", key); long ts = cache.NextTimestamp() + cache.Timeout; // create new lock that times out immediately - CacheLock @lock = new CacheLock(ts, NextLockId(), null); + CacheLock @lock = CacheLock.Create(ts, NextLockId(), null); @lock.Unlock(ts); return cache.PutAsync(key, @lock, cancellationToken); } @@ -311,7 +311,7 @@ public async Task AfterUpdateAsync(CacheKey key, object value, object vers else { //recache the updated state - await (cache.PutAsync(key, new CachedItem(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Updated: {0}", key); @@ -349,7 +349,7 @@ public async Task AfterInsertAsync(CacheKey key, object value, object vers ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (lockable == null) { - await (cache.PutAsync(key, new CachedItem(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Inserted: {0}", key); diff --git a/src/NHibernate/Async/Engine/Loading/CollectionLoadContext.cs b/src/NHibernate/Async/Engine/Loading/CollectionLoadContext.cs index b13ba5576e4..4e40757dbde 100644 --- a/src/NHibernate/Async/Engine/Loading/CollectionLoadContext.cs +++ b/src/NHibernate/Async/Engine/Loading/CollectionLoadContext.cs @@ -219,7 +219,7 @@ private async Task AddCollectionToCacheAsync(LoadingCollectionEntry lce, ICollec versionComparator = null; } - CollectionCacheEntry entry = new CollectionCacheEntry(lce.Collection, persister); + CollectionCacheEntry entry = await (CollectionCacheEntry.CreateAsync(lce.Collection, persister, cancellationToken)).ConfigureAwait(false); CacheKey cacheKey = session.GenerateCacheKey(lce.Key, persister.KeyType, persister.Role); bool put = await (persister.Cache.PutAsync(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, versionComparator, diff --git a/src/NHibernate/Async/Engine/TwoPhaseLoad.cs b/src/NHibernate/Async/Engine/TwoPhaseLoad.cs index 6579b270c6f..96f199c9188 100644 --- a/src/NHibernate/Async/Engine/TwoPhaseLoad.cs +++ b/src/NHibernate/Async/Engine/TwoPhaseLoad.cs @@ -93,7 +93,7 @@ public static async Task InitializeEntityAsync(object entity, bool readOnly, ISe object version = Versioning.GetVersion(hydratedState, persister); CacheEntry entry = - new CacheEntry(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity); + await (CacheEntry.CreateAsync(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity, cancellationToken)).ConfigureAwait(false); CacheKey cacheKey = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); bool put = await (persister.Cache.PutAsync(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, diff --git a/src/NHibernate/Async/Type/AnyType.cs b/src/NHibernate/Async/Type/AnyType.cs index 57347f1c602..bc44efe796b 100644 --- a/src/NHibernate/Async/Type/AnyType.cs +++ b/src/NHibernate/Async/Type/AnyType.cs @@ -18,6 +18,7 @@ using NHibernate.SqlTypes; using NHibernate.Util; using System.Collections.Generic; +using System.Runtime.Serialization; namespace NHibernate.Type { @@ -41,9 +42,11 @@ public override async Task NullSafeGetAsync(DbDataReader rs, string[] na public override async Task HydrateAsync(DbDataReader rs, string[] names, ISessionImplementor session, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - string entityName = (string)await (metaType.NullSafeGetAsync(rs, names[0], session, owner, cancellationToken)).ConfigureAwait(false); - object id = await (identifierType.NullSafeGetAsync(rs, names[1], session, owner, cancellationToken)).ConfigureAwait(false); - return new ObjectTypeCacheEntry(entityName, id); + return new ObjectTypeCacheEntry + { + Id = await (identifierType.NullSafeGetAsync(rs, names[1], session, owner, cancellationToken)).ConfigureAwait(false), + EntityName = (string) await (metaType.NullSafeGetAsync(rs, names[0], session, owner, cancellationToken)).ConfigureAwait(false) + }; } public override Task ResolveIdentifierAsync(object value, ISessionImplementor session, object owner, CancellationToken cancellationToken) @@ -55,7 +58,7 @@ public override Task ResolveIdentifierAsync(object value, ISessionImplem try { ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) value; - return ResolveAnyAsync(holder.entityName, holder.id, session, cancellationToken); + return ResolveAnyAsync(holder.EntityName, holder.Id, session, cancellationToken); } catch (Exception ex) { @@ -119,7 +122,7 @@ public override Task AssembleAsync(object cached, ISessionImplementor se try { ObjectTypeCacheEntry e = cached as ObjectTypeCacheEntry; - return (e == null) ? Task.FromResult(null ): session.InternalLoadAsync(e.entityName, e.id, false, false, cancellationToken); + return (e == null) ? Task.FromResult(null ): session.InternalLoadAsync(e.EntityName, e.Id, false, false, cancellationToken); } catch (Exception ex) { @@ -130,9 +133,13 @@ public override Task AssembleAsync(object cached, ISessionImplementor se public override async Task DisassembleAsync(object value, ISessionImplementor session, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - return value == null ? null : - new ObjectTypeCacheEntry(session.BestGuessEntityName(value), - await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(session.BestGuessEntityName(value), value, session, cancellationToken)).ConfigureAwait(false)); + return value == null + ? null + : new ObjectTypeCacheEntry + { + EntityName = session.BestGuessEntityName(value), + Id = await (ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(session.BestGuessEntityName(value), value, session, cancellationToken)).ConfigureAwait(false) + }; } public override async Task ReplaceAsync(object original, object current, ISessionImplementor session, object owner, @@ -206,8 +213,8 @@ public override async Task IsModifiedAsync(object old, object current, boo ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry)old; bool[] idcheckable = new bool[checkable.Length - 1]; Array.Copy(checkable, 1, idcheckable, 0, idcheckable.Length); - return (checkable[0] && !holder.entityName.Equals(session.BestGuessEntityName(current))) || - await (identifierType.IsModifiedAsync(holder.id, await (IdAsync(current, session, cancellationToken)).ConfigureAwait(false), idcheckable, session, cancellationToken)).ConfigureAwait(false); + return (checkable[0] && !holder.EntityName.Equals(session.BestGuessEntityName(current))) || + await (identifierType.IsModifiedAsync(holder.Id, await (IdAsync(current, session, cancellationToken)).ConfigureAwait(false), idcheckable, session, cancellationToken)).ConfigureAwait(false); } private Task ResolveAnyAsync(string entityName, object id, ISessionImplementor session, CancellationToken cancellationToken) diff --git a/src/NHibernate/Cache/CacheLock.cs b/src/NHibernate/Cache/CacheLock.cs index 3b34986c335..f122cbd35b6 100644 --- a/src/NHibernate/Cache/CacheLock.cs +++ b/src/NHibernate/Cache/CacheLock.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Runtime.Serialization; using NHibernate.Cache.Access; namespace NHibernate.Cache @@ -12,20 +13,37 @@ namespace NHibernate.Cache /// This class was named Lock in H2.1 /// [Serializable] + [DataContract] public class CacheLock : ReadWriteCache.ILockable, ISoftLock { private long unlockTimestamp = -1; private int multiplicity = 1; private bool concurrentLock = false; private long timeout; - private readonly int id; - private readonly object version; + private int id; + private object version; + public CacheLock() + { + } + + // Since 5.2 + [Obsolete("Use object initializer instead.")] public CacheLock(long timeout, int id, object version) { - this.timeout = timeout; - this.id = id; - this.version = version; + Timeout = timeout; + Id = id; + Version = version; + } + + internal static CacheLock Create(long timeout, int id, object version) + { + return new CacheLock + { + Version = version, + Timeout = timeout, + Id = id + }; } /// @@ -34,9 +52,9 @@ public CacheLock(long timeout, int id, object version) /// public CacheLock Lock(long timeout, int id) { - concurrentLock = true; - multiplicity++; - this.timeout = timeout; + WasLockedConcurrently = true; + Multiplicity++; + Timeout = timeout; return this; } @@ -47,9 +65,9 @@ public CacheLock Lock(long timeout, int id) /// public void Unlock(long currentTimestamp) { - if (--multiplicity == 0) + if (--Multiplicity == 0) { - unlockTimestamp = currentTimestamp; + UnlockTimestamp = currentTimestamp; } } @@ -59,17 +77,17 @@ public void Unlock(long currentTimestamp) /// public bool IsPuttable(long txTimestamp, object newVersion, IComparer comparator) { - if (timeout < txTimestamp) + if (Timeout < txTimestamp) { return true; } - if (multiplicity > 0) + if (Multiplicity > 0) { return false; } - return version == null ? - unlockTimestamp < txTimestamp : - comparator.Compare(version, newVersion) < 0; + return Version == null ? + UnlockTimestamp < txTimestamp : + comparator.Compare(Version, newVersion) < 0; //by requiring <, we rely on lock timeout in the case of an unsuccessful update! } @@ -77,18 +95,18 @@ public bool IsPuttable(long txTimestamp, object newVersion, IComparer comparator /// Was this lock held concurrently by multiple /// transactions? /// + // 6.0 TODO convert to auto-property + [DataMember] public bool WasLockedConcurrently { - get { return concurrentLock; } + get => concurrentLock; + set => concurrentLock = value; } /// /// Yes, this is a lock /// - public bool IsLock - { - get { return true; } - } + public bool IsLock => true; /// /// locks are not returned to the client! @@ -98,18 +116,53 @@ public bool IsGettable(long txTimestamp) return false; } + // 6.0 TODO convert to auto-property + [DataMember] public int Id { - get { return id; } + get => id; + set => id = value; + } + + // 6.0 TODO convert to auto-property + [DataMember] + public object Version + { + get => version; + set => version = value; + } + + // 6.0 TODO convert to auto-property + [DataMember] + public long UnlockTimestamp + { + get => unlockTimestamp; + set => unlockTimestamp = value; + } + + // 6.0 TODO convert to auto-property + [DataMember] + public int Multiplicity + { + get => multiplicity; + set => multiplicity = value; + } + + // 6.0 TODO convert to auto-property + [DataMember] + public long Timeout + { + get => timeout; + set => timeout = value; } public override string ToString() { - return "CacheLock{id=" + id + - ",version=" + version + - ",multiplicity=" + multiplicity + - ",unlockTimestamp=" + unlockTimestamp + + return "CacheLock{id=" + Id + + ",version=" + Version + + ",multiplicity=" + Multiplicity + + ",unlockTimestamp=" + UnlockTimestamp + "}"; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Cache/CachedItem.cs b/src/NHibernate/Cache/CachedItem.cs index 50448351e0f..b92e45c66a3 100644 --- a/src/NHibernate/Cache/CachedItem.cs +++ b/src/NHibernate/Cache/CachedItem.cs @@ -1,5 +1,8 @@ using System; using System.Collections; +using System.Runtime.Serialization; +using System.Xml.Serialization; +using NHibernate.Cache.Entry; namespace NHibernate.Cache { @@ -8,33 +11,71 @@ namespace NHibernate.Cache /// when it was unlocked /// [Serializable] + [XmlInclude(typeof(CacheEntry))] + [XmlInclude(typeof(CollectionCacheEntry))] + [DataContract] + [KnownType(typeof(CacheEntry))] + [KnownType(typeof(CollectionCacheEntry))] public class CachedItem : ReadWriteCache.ILockable { - private readonly long freshTimestamp; - private readonly object value; - private readonly object version; + private long freshTimestamp; + private object value; + private object version; + public CachedItem() + { + } + + // Since 5.2 + [Obsolete("Use object initializer instead.")] public CachedItem(object value, long currentTimestamp, object version) { - this.value = value; - freshTimestamp = currentTimestamp; - this.version = version; + Value = value; + FreshTimestamp = currentTimestamp; + Version = version; + } + + internal static CachedItem Create(object value, long currentTimestamp, object version) + { + return new CachedItem + { + Version = version, + FreshTimestamp = currentTimestamp, + Value = value + }; } /// /// The timestamp on the cached data /// + // 6.0 TODO convert to auto-property + [DataMember] public long FreshTimestamp { - get { return freshTimestamp; } + get => freshTimestamp; + set => freshTimestamp = value; } /// /// The actual cached data /// + // 6.0 TODO convert to auto-property + [DataMember] public object Value { - get { return value; } + get => value; + set => this.value = value; + } + + /// + /// The version of the cached data + /// + // 6.0 TODO convert to auto-property + [DataMember] + public object Version + { + get => version; + set => version = value; } /// @@ -42,7 +83,7 @@ public object Value /// public CacheLock Lock(long timeout, int id) { - return new CacheLock(timeout, id, version); + return CacheLock.Create(timeout, id, Version); } /// @@ -60,7 +101,7 @@ public bool IsLock /// public bool IsGettable(long txTimestamp) { - return freshTimestamp < txTimestamp; + return FreshTimestamp < txTimestamp; } /// @@ -75,13 +116,13 @@ public bool IsPuttable(long txTimestamp, object newVersion, IComparer comparator // we really could refresh the item if it // is not a lock, but it might be slower //return freshTimestamp < txTimestamp - return version != null && comparator.Compare(version, newVersion) < 0; + return Version != null && comparator.Compare(Version, newVersion) < 0; } public override string ToString() { - return "Item{version=" + version + - ",freshTimestamp=" + freshTimestamp + + return "Item{version=" + Version + + ",freshTimestamp=" + FreshTimestamp + "}"; } } diff --git a/src/NHibernate/Cache/Entry/CacheEntry.cs b/src/NHibernate/Cache/Entry/CacheEntry.cs index cba2abddb67..8580f3496b3 100644 --- a/src/NHibernate/Cache/Entry/CacheEntry.cs +++ b/src/NHibernate/Cache/Entry/CacheEntry.cs @@ -1,7 +1,11 @@ using System; +using System.Runtime.Serialization; +using System.Xml.Serialization; using NHibernate.Engine; using NHibernate.Event; +using NHibernate.Intercept; using NHibernate.Persister.Entity; +using NHibernate.Properties; using NHibernate.Type; namespace NHibernate.Cache.Entry @@ -10,66 +14,94 @@ namespace NHibernate.Cache.Entry /// A cached instance of a persistent class /// [Serializable] + [XmlInclude(typeof(AnyType.ObjectTypeCacheEntry))] + [XmlInclude(typeof(UnfetchedLazyProperty))] + [XmlInclude(typeof(UnknownBackrefProperty))] + [DataContract] + [KnownType(typeof(AnyType.ObjectTypeCacheEntry))] + [KnownType(typeof(DateTimeOffset))] + [KnownType(typeof(TimeSpan))] + [KnownType(typeof(UnfetchedLazyProperty))] + [KnownType(typeof(UnknownBackrefProperty))] public sealed partial class CacheEntry { - private readonly object[] disassembledState; - private readonly string subclass; - private readonly bool lazyPropertiesAreUnfetched; - private readonly object version; + private object[] disassembledState; + private string subclass; + private bool lazyPropertiesAreUnfetched; + private object version; + public CacheEntry() + { + } + // Since 5.2 + [Obsolete("Please use CacheEntry.Create method instead.")] public CacheEntry(object[] state, IEntityPersister persister, bool unfetched, object version, ISessionImplementor session, object owner) { //disassembled state gets put in a new array (we write to cache by value!) - disassembledState = TypeHelper.Disassemble(state, persister.PropertyTypes, null, session, owner); - subclass = persister.EntityName; - lazyPropertiesAreUnfetched = unfetched || !persister.IsLazyPropertiesCacheable; - this.version = version; + DisassembledState = TypeHelper.Disassemble(state, persister.PropertyTypes, null, session, owner); + Subclass = persister.EntityName; + AreLazyPropertiesUnfetched = unfetched || !persister.IsLazyPropertiesCacheable; + Version = version; } - internal CacheEntry(object[] state, string subclass, bool unfetched, object version) + public static CacheEntry Create(object[] state, IEntityPersister persister, bool unfetched, object version, + ISessionImplementor session, object owner) { - disassembledState = state; - this.subclass = subclass; - lazyPropertiesAreUnfetched = unfetched; - this.version = version; + return new CacheEntry + { + //disassembled state gets put in a new array (we write to cache by value!) + DisassembledState = TypeHelper.Disassemble(state, persister.PropertyTypes, null, session, owner), + AreLazyPropertiesUnfetched = unfetched || !persister.IsLazyPropertiesCacheable, + Subclass = persister.EntityName, + Version = version + }; } + // 6.0 TODO convert to auto-property + [DataMember] public object Version { - get{return version;} + get => version; + set => version = value; } + // 6.0 TODO convert to auto-property + [DataMember] public string Subclass { - get { return subclass; } + get => subclass; + set => subclass = value; } + // 6.0 TODO convert to auto-property + [DataMember] public bool AreLazyPropertiesUnfetched { - get { return lazyPropertiesAreUnfetched; } + get => lazyPropertiesAreUnfetched; + set => lazyPropertiesAreUnfetched = value; } + // todo: this was added to support initializing an entity's EntityEntry snapshot during reattach; + // this should be refactored to instead expose a method to assemble a EntityEntry based on this + // state for return. + // 6.0 TODO convert to auto-property + [DataMember] public object[] DisassembledState { - get - { - // todo: this was added to support initializing an entity's EntityEntry snapshot during reattach; - // this should be refactored to instead expose a method to assemble a EntityEntry based on this - // state for return. - return disassembledState; - } + get => disassembledState; + set => disassembledState = value; } public object[] Assemble(object instance, object id, IEntityPersister persister, IInterceptor interceptor, ISessionImplementor session) { - if (!persister.EntityName.Equals(subclass)) + if (!persister.EntityName.Equals(Subclass)) { throw new AssertionFailure("Tried to assemble a different subclass instance"); } - return Assemble(disassembledState, instance, id, persister, interceptor, session); + return Assemble(DisassembledState, instance, id, persister, interceptor, session); } private static object[] Assemble(object[] values, object result, object id, IEntityPersister persister, @@ -96,4 +128,4 @@ private static object[] Assemble(object[] values, object result, object id, IEnt return assembledProps; } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs index 84533511d54..182a3e8db02 100644 --- a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs @@ -1,39 +1,76 @@ using System; +using System.Runtime.Serialization; +using System.Xml.Serialization; using NHibernate.Collection; +using NHibernate.Intercept; using NHibernate.Persister.Collection; +using NHibernate.Properties; +using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Cache.Entry { [Serializable] + [XmlInclude(typeof(AnyType.ObjectTypeCacheEntry))] + [XmlInclude(typeof(object[]))] + [XmlInclude(typeof(UnfetchedLazyProperty))] + [XmlInclude(typeof(UnknownBackrefProperty))] + [DataContract] + [KnownType(typeof(AnyType.ObjectTypeCacheEntry))] + [KnownType(typeof(object[]))] + [KnownType(typeof(DateTimeOffset))] + [KnownType(typeof(TimeSpan))] + [KnownType(typeof(UnfetchedLazyProperty))] + [KnownType(typeof(UnknownBackrefProperty))] public partial class CollectionCacheEntry { - private readonly object state; + private object state; + public CollectionCacheEntry() + { + } + + // Since 5.2 + [Obsolete("Use CollectionCacheEntry.Create method instead.")] public CollectionCacheEntry(IPersistentCollection collection, ICollectionPersister persister) { - state = collection.Disassemble(persister); + DisassembledState = collection.Disassemble(persister); } - internal CollectionCacheEntry(object state) + public static CollectionCacheEntry Create(IPersistentCollection collection, ICollectionPersister persister) { - this.state = state; + return new CollectionCacheEntry + { + DisassembledState = collection.Disassemble(persister) + }; } - public virtual object[] State + // 6.0 TODO convert to auto-property + [DataMember] + public object DisassembledState { - get { return (object[])state; }//TODO: assumes all collections disassemble to an array! + get => state; + set => state = value; } + //TODO: assumes all collections disassemble to an array! + [Obsolete("Please use DisassembledState property instead.")] + public virtual object[] State => (object[]) DisassembledState; + public virtual void Assemble(IPersistentCollection collection, ICollectionPersister persister, object owner) { - collection.InitializeFromCache(persister, state, owner); + collection.InitializeFromCache(persister, DisassembledState, owner); collection.AfterInitialize(persister); } public override string ToString() { - return "CollectionCacheEntry" + ArrayHelper.ToString(State); + if (DisassembledState is object[] array) + { + return "CollectionCacheEntry" + ArrayHelper.ToString(array); + } + return "CollectionCacheEntry" + StringHelper.Unqualify(DisassembledState.GetType().FullName) + "@" + + DisassembledState.GetHashCode(); } } } diff --git a/src/NHibernate/Cache/Entry/StructuredCacheEntry.cs b/src/NHibernate/Cache/Entry/StructuredCacheEntry.cs index f9b7e30f62b..bc9bf20372a 100644 --- a/src/NHibernate/Cache/Entry/StructuredCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/StructuredCacheEntry.cs @@ -28,7 +28,13 @@ public object Destructure(object item, ISessionFactoryImplementor factory) { state[i] = map[names[i]]; } - return new CacheEntry(state, subclass, lazyPropertiesUnfetched, version); + return new CacheEntry + { + Subclass = subclass, + DisassembledState = state, + Version = version, + AreLazyPropertiesUnfetched = lazyPropertiesUnfetched + }; } public object Structure(object item) diff --git a/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs b/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs index e85c6828694..f4b57fde4b1 100644 --- a/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs @@ -11,7 +11,7 @@ public class StructuredCollectionCacheEntry : ICacheEntryStructure public virtual object Structure(object item) { var entry = (CollectionCacheEntry)item; - return new List(entry.State); + return new List((object[])entry.DisassembledState); } public virtual object Destructure(object item, ISessionFactoryImplementor factory) @@ -20,7 +20,7 @@ public virtual object Destructure(object item, ISessionFactoryImplementor factor var objects = collection != null ? collection.Cast().ToArray() : Array.Empty(); - return new CollectionCacheEntry(objects); + return new CollectionCacheEntry {DisassembledState = objects}; } } } diff --git a/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs b/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs index 169af790f22..decc60f1d24 100644 --- a/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs @@ -8,7 +8,7 @@ public class StructuredMapCacheEntry : ICacheEntryStructure public object Structure(object item) { CollectionCacheEntry entry = (CollectionCacheEntry)item; - object[] state = entry.State; + object[] state = (object[])entry.DisassembledState; IDictionary map = new Hashtable(state.Length); for (int i = 0; i < state.Length; ) { @@ -27,7 +27,7 @@ public object Destructure(object item, ISessionFactoryImplementor factory) state[i++] = me.Key; state[i++] = me.Value; } - return new CollectionCacheEntry(state); + return new CollectionCacheEntry {DisassembledState = state}; } } } diff --git a/src/NHibernate/Cache/ReadWriteCache.cs b/src/NHibernate/Cache/ReadWriteCache.cs index 98da04caa17..a79867e65c3 100644 --- a/src/NHibernate/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Cache/ReadWriteCache.cs @@ -159,7 +159,7 @@ public ISoftLock Lock(CacheKey key, object version) ILockable lockable = (ILockable) cache.Get(key); long timeout = cache.NextTimestamp() + cache.Timeout; CacheLock @lock = lockable == null ? - new CacheLock(timeout, NextLockId(), version) : + CacheLock.Create(timeout, NextLockId(), version) : lockable.Lock(timeout, NextLockId()); cache.Put(key, @lock); return @lock; @@ -205,7 +205,7 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC if (puttable) { - cache.Put(key, new CachedItem(value, cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -280,7 +280,7 @@ internal void HandleLockExpiry(object key) log.Warn("An item was expired by the cache while it was locked (increase your cache timeout): {0}", key); long ts = cache.NextTimestamp() + cache.Timeout; // create new lock that times out immediately - CacheLock @lock = new CacheLock(ts, NextLockId(), null); + CacheLock @lock = CacheLock.Create(ts, NextLockId(), null); @lock.Unlock(ts); cache.Put(key, @lock); } @@ -337,7 +337,7 @@ public bool AfterUpdate(CacheKey key, object value, object version, ISoftLock cl else { //recache the updated state - cache.Put(key, new CachedItem(value, cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Updated: {0}", key); @@ -374,7 +374,7 @@ public bool AfterInsert(CacheKey key, object value, object version) ILockable lockable = (ILockable) cache.Get(key); if (lockable == null) { - cache.Put(key, new CachedItem(value, cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Inserted: {0}", key); diff --git a/src/NHibernate/Engine/Loading/CollectionLoadContext.cs b/src/NHibernate/Engine/Loading/CollectionLoadContext.cs index 2e7604d4948..ddfb0456c6c 100644 --- a/src/NHibernate/Engine/Loading/CollectionLoadContext.cs +++ b/src/NHibernate/Engine/Loading/CollectionLoadContext.cs @@ -325,7 +325,7 @@ private void AddCollectionToCache(LoadingCollectionEntry lce, ICollectionPersist versionComparator = null; } - CollectionCacheEntry entry = new CollectionCacheEntry(lce.Collection, persister); + CollectionCacheEntry entry = CollectionCacheEntry.Create(lce.Collection, persister); CacheKey cacheKey = session.GenerateCacheKey(lce.Key, persister.KeyType, persister.Role); bool put = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, versionComparator, diff --git a/src/NHibernate/Engine/TwoPhaseLoad.cs b/src/NHibernate/Engine/TwoPhaseLoad.cs index 54786a29d4e..7eb3ada4380 100644 --- a/src/NHibernate/Engine/TwoPhaseLoad.cs +++ b/src/NHibernate/Engine/TwoPhaseLoad.cs @@ -105,7 +105,7 @@ public static void InitializeEntity(object entity, bool readOnly, ISessionImplem object version = Versioning.GetVersion(hydratedState, persister); CacheEntry entry = - new CacheEntry(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity); + CacheEntry.Create(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity); CacheKey cacheKey = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); bool put = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, diff --git a/src/NHibernate/Type/AnyType.cs b/src/NHibernate/Type/AnyType.cs index 8e1e824c545..df64defc070 100644 --- a/src/NHibernate/Type/AnyType.cs +++ b/src/NHibernate/Type/AnyType.cs @@ -8,6 +8,7 @@ using NHibernate.SqlTypes; using NHibernate.Util; using System.Collections.Generic; +using System.Runtime.Serialization; namespace NHibernate.Type { @@ -95,15 +96,17 @@ public override object NullSafeGet(DbDataReader rs, string[] names, ISessionImpl public override object Hydrate(DbDataReader rs, string[] names, ISessionImplementor session, object owner) { - string entityName = (string)metaType.NullSafeGet(rs, names[0], session, owner); - object id = identifierType.NullSafeGet(rs, names[1], session, owner); - return new ObjectTypeCacheEntry(entityName, id); + return new ObjectTypeCacheEntry + { + Id = identifierType.NullSafeGet(rs, names[1], session, owner), + EntityName = (string) metaType.NullSafeGet(rs, names[0], session, owner) + }; } public override object ResolveIdentifier(object value, ISessionImplementor session, object owner) { ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) value; - return ResolveAny(holder.entityName, holder.id, session); + return ResolveAny(holder.EntityName, holder.Id, session); } public override object SemiResolve(object value, ISessionImplementor session, object owner) @@ -165,28 +168,44 @@ public override string ToLoggableString(object value, ISessionFactoryImplementor } [Serializable] + [DataContract] public sealed class ObjectTypeCacheEntry { internal string entityName; internal object id; - internal ObjectTypeCacheEntry(string entityName, object id) + + // 6.0 TODO convert to auto-property + [DataMember] + public string EntityName + { + get => entityName; + set => entityName = value; + } + + // 6.0 TODO convert to auto-property + [DataMember] + public object Id { - this.entityName = entityName; - this.id = id; + get => id; + set => id = value; } } public override object Assemble(object cached, ISessionImplementor session, object owner) { ObjectTypeCacheEntry e = cached as ObjectTypeCacheEntry; - return (e == null) ? null : session.InternalLoad(e.entityName, e.id, false, false); + return (e == null) ? null : session.InternalLoad(e.EntityName, e.Id, false, false); } public override object Disassemble(object value, ISessionImplementor session, object owner) { - return value == null ? null : - new ObjectTypeCacheEntry(session.BestGuessEntityName(value), - ForeignKeys.GetEntityIdentifierIfNotUnsaved(session.BestGuessEntityName(value), value, session)); + return value == null + ? null + : new ObjectTypeCacheEntry + { + EntityName = session.BestGuessEntityName(value), + Id = ForeignKeys.GetEntityIdentifierIfNotUnsaved(session.BestGuessEntityName(value), value, session) + }; } public override object Replace(object original, object current, ISessionImplementor session, object owner, @@ -345,8 +364,8 @@ public override bool IsModified(object old, object current, bool[] checkable, IS ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry)old; bool[] idcheckable = new bool[checkable.Length - 1]; Array.Copy(checkable, 1, idcheckable, 0, idcheckable.Length); - return (checkable[0] && !holder.entityName.Equals(session.BestGuessEntityName(current))) || - identifierType.IsModified(holder.id, Id(current, session), idcheckable, session); + return (checkable[0] && !holder.EntityName.Equals(session.BestGuessEntityName(current))) || + identifierType.IsModified(holder.Id, Id(current, session), idcheckable, session); } public bool[] PropertyNullability From 35574d45fbd9f877c23531587028f492bf14c3cb Mon Sep 17 00:00:00 2001 From: maca88 Date: Thu, 28 Jun 2018 18:47:46 +0200 Subject: [PATCH 2/3] Removed XmlInclude and KnownType attributes and removed XmlSerializer from tests --- .../Async/CacheTest/SerializationFixture.cs | 96 +++++-------------- .../CacheTest/SerializationFixture.cs | 95 +++++------------- .../Async/Cache/Entry/CacheEntry.cs | 3 - .../Async/Cache/Entry/CollectionCacheEntry.cs | 4 - src/NHibernate/Async/Cache/ReadWriteCache.cs | 2 +- src/NHibernate/Cache/CachedItem.cs | 6 -- src/NHibernate/Cache/Entry/CacheEntry.cs | 11 --- .../Cache/Entry/CollectionCacheEntry.cs | 14 --- src/NHibernate/Cache/ReadWriteCache.cs | 2 +- 9 files changed, 49 insertions(+), 184 deletions(-) diff --git a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs index 5890c7cceaa..b48bc6ba908 100644 --- a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs @@ -9,7 +9,6 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -17,15 +16,12 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; -using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -using System.Xml.Serialization; using NHibernate.Cache; using NHibernate.Cache.Entry; using NHibernate.Engine; using NHibernate.Intercept; -using NHibernate.Persister.Entity; using NHibernate.Properties; using NHibernate.Type; using NSubstitute; @@ -33,69 +29,63 @@ namespace NHibernate.Test.CacheTest { + using System.Threading.Tasks; [TestFixture] public class SerializationFixtureAsync { - // XmlSerializer does not support DateTimeOffset and TimeSpan types - private readonly Func, bool> _xmlSerializerTypePredicate = - o => !(o.Value is DateTimeOffset) && !(o.Value is TimeSpan); + private static readonly List KnownTypes = new List + { + typeof(AnyType.ObjectTypeCacheEntry), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(UnfetchedLazyProperty), + typeof(UnknownBackrefProperty), + typeof(object[]), + typeof(CacheEntry), + typeof(CacheLock), + typeof(CollectionCacheEntry) + }; [Test] public async Task TestCacheEntrySerializationAsync() { - var item = CreateCacheEntry(null); + var item = CreateCacheEntry(); var copy = await (TestDataContractSerializerAsync(item)); CheckCacheEntry(item, copy); copy = TestBinaryFormatter(item); CheckCacheEntry(item, copy); - - item = CreateCacheEntry(_xmlSerializerTypePredicate); - copy = TestXmlSerializer(item); - CheckCacheEntry(item, copy); } [Test] public async Task TestCollectionCacheEntrySerializationAsync() { - var item = CreateCollectionCacheEntry(null); + var item = CreateCollectionCacheEntry(); var copy = await (TestDataContractSerializerAsync(item)); CheckCollectionCacheEntry(item, copy); copy = TestBinaryFormatter(item); CheckCollectionCacheEntry(item, copy); - - item = CreateCollectionCacheEntry(_xmlSerializerTypePredicate); - copy = TestXmlSerializer(item); - CheckCollectionCacheEntry(item, copy); } [Test] public async Task TestCachedItemSerializationAsync() { // CacheEntry - var item = CreateCachedItem(CreateCacheEntry(null)); + var item = CreateCachedItem(CreateCacheEntry()); var copy = await (TestDataContractSerializerAsync(item)); CheckCachedItem(item, copy); copy = TestBinaryFormatter(item); CheckCachedItem(item, copy); - item = CreateCachedItem(CreateCacheEntry(_xmlSerializerTypePredicate)); - copy = TestXmlSerializer(item); - CheckCachedItem(item, copy); - // CollectionCacheEntry - item = CreateCachedItem(CreateCollectionCacheEntry(null)); + item = CreateCachedItem(CreateCollectionCacheEntry()); copy = await (TestDataContractSerializerAsync(item)); CheckCachedItem(item, copy); copy = TestBinaryFormatter(item); CheckCachedItem(item, copy); - - item = CreateCachedItem(CreateCollectionCacheEntry(_xmlSerializerTypePredicate)); - copy = TestXmlSerializer(item); - CheckCachedItem(item, copy); } [Test] @@ -115,9 +105,6 @@ public async Task TestCacheLockSerializationAsync() copy = TestBinaryFormatter(item); CheckCacheLock(item, copy); - - copy = TestXmlSerializer(item); - CheckCacheLock(item, copy); } [Test] @@ -129,9 +116,6 @@ public async Task TestAnyTypeObjectTypeCacheEntrySerializationAsync() copy = TestBinaryFormatter(item); CheckObjectTypeCacheEntry(item, copy); - - copy = TestXmlSerializer(item); - CheckObjectTypeCacheEntry(item, copy); } @@ -151,26 +135,26 @@ private CachedItem CreateCachedItem(object value) }; } - private CacheEntry CreateCacheEntry(Func, bool> predicate) + private CacheEntry CreateCacheEntry() { return new CacheEntry { - DisassembledState = GetAllKnownTypeValues(predicate), + DisassembledState = GetAllKnownTypeValues(), Version = 55, Subclass = "Test", AreLazyPropertiesUnfetched = true }; } - private CollectionCacheEntry CreateCollectionCacheEntry(Func, bool> predicate) + private CollectionCacheEntry CreateCollectionCacheEntry() { return new CollectionCacheEntry { - DisassembledState = GetAllKnownTypeValues(predicate) + DisassembledState = GetAllKnownTypeValues() }; } - private object[] GetAllKnownTypeValues(Func, bool> predicate) + private object[] GetAllKnownTypeValues() { var entityName = nameof(MyEntity); var xmlDoc = new XmlDocument(); @@ -222,10 +206,6 @@ private object[] GetAllKnownTypeValues(Func, bool> p {NHibernateUtil.XDoc, XDocument.Parse("XDoc")}, {NHibernateUtil.Uri, new Uri("http://test.com")} }; - if (predicate != null) - { - types = types.Where(predicate).ToDictionary(o => o.Key, o => o.Value); - } var sessionImpl = Substitute.For(); sessionImpl.BestGuessEntityName(Arg.Any()).Returns(o => o[0].GetType().Name); @@ -342,14 +322,6 @@ private static async Task TestDataContractSerializerAsync(T obj) return obj; } - private static T TestXmlSerializer(T obj) - { - var xml = XmlSerializerToXml(obj); - obj = XmlSerializerFromXml(xml); - Assert.That(xml, Is.EqualTo(XmlSerializerToXml(obj))); - return obj; - } - private static T TestBinaryFormatter(T obj) { var bytes = BinaryFormatterToBinary(obj); @@ -363,8 +335,7 @@ private static async Task DataContractSerializerToXmlAsync(T obj) using (var memoryStream = new MemoryStream()) using (var reader = new StreamReader(memoryStream)) { - - var serializer = new DataContractSerializer(typeof(T)); + var serializer = new DataContractSerializer(typeof(T), KnownTypes); serializer.WriteObject(memoryStream, obj); memoryStream.Position = 0; return await (reader.ReadToEndAsync()); @@ -378,30 +349,11 @@ private static T DataContractSerializerFromXml(string xml) var data = Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; - var deserializer = new DataContractSerializer(typeof(T)); + var deserializer = new DataContractSerializer(typeof(T), KnownTypes); return (T) deserializer.ReadObject(stream); } } - private static string XmlSerializerToXml(T obj) - { - var serializer = new XmlSerializer(typeof(T)); - using (var writer = new StringWriter()) - { - serializer.Serialize(writer, obj); - return writer.ToString(); - } - } - - private static T XmlSerializerFromXml(string xml) - { - var serializer = new XmlSerializer(typeof(T)); - using (var reader = new StringReader(xml)) - { - return (T) serializer.Deserialize(reader); - } - } - private static byte[] BinaryFormatterToBinary(T obj) { var serializer = new BinaryFormatter(); diff --git a/src/NHibernate.Test/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/CacheTest/SerializationFixture.cs index 7aa98db5a7e..82abb428a36 100644 --- a/src/NHibernate.Test/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/CacheTest/SerializationFixture.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -7,15 +6,12 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; -using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -using System.Xml.Serialization; using NHibernate.Cache; using NHibernate.Cache.Entry; using NHibernate.Engine; using NHibernate.Intercept; -using NHibernate.Persister.Entity; using NHibernate.Properties; using NHibernate.Type; using NSubstitute; @@ -26,66 +22,59 @@ namespace NHibernate.Test.CacheTest [TestFixture] public class SerializationFixture { - // XmlSerializer does not support DateTimeOffset and TimeSpan types - private readonly Func, bool> _xmlSerializerTypePredicate = - o => !(o.Value is DateTimeOffset) && !(o.Value is TimeSpan); + private static readonly List KnownTypes = new List + { + typeof(AnyType.ObjectTypeCacheEntry), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(UnfetchedLazyProperty), + typeof(UnknownBackrefProperty), + typeof(object[]), + typeof(CacheEntry), + typeof(CacheLock), + typeof(CollectionCacheEntry) + }; [Test] public void TestCacheEntrySerialization() { - var item = CreateCacheEntry(null); + var item = CreateCacheEntry(); var copy = TestDataContractSerializer(item); CheckCacheEntry(item, copy); copy = TestBinaryFormatter(item); CheckCacheEntry(item, copy); - - item = CreateCacheEntry(_xmlSerializerTypePredicate); - copy = TestXmlSerializer(item); - CheckCacheEntry(item, copy); } [Test] public void TestCollectionCacheEntrySerialization() { - var item = CreateCollectionCacheEntry(null); + var item = CreateCollectionCacheEntry(); var copy = TestDataContractSerializer(item); CheckCollectionCacheEntry(item, copy); copy = TestBinaryFormatter(item); CheckCollectionCacheEntry(item, copy); - - item = CreateCollectionCacheEntry(_xmlSerializerTypePredicate); - copy = TestXmlSerializer(item); - CheckCollectionCacheEntry(item, copy); } [Test] public void TestCachedItemSerialization() { // CacheEntry - var item = CreateCachedItem(CreateCacheEntry(null)); + var item = CreateCachedItem(CreateCacheEntry()); var copy = TestDataContractSerializer(item); CheckCachedItem(item, copy); copy = TestBinaryFormatter(item); CheckCachedItem(item, copy); - item = CreateCachedItem(CreateCacheEntry(_xmlSerializerTypePredicate)); - copy = TestXmlSerializer(item); - CheckCachedItem(item, copy); - // CollectionCacheEntry - item = CreateCachedItem(CreateCollectionCacheEntry(null)); + item = CreateCachedItem(CreateCollectionCacheEntry()); copy = TestDataContractSerializer(item); CheckCachedItem(item, copy); copy = TestBinaryFormatter(item); CheckCachedItem(item, copy); - - item = CreateCachedItem(CreateCollectionCacheEntry(_xmlSerializerTypePredicate)); - copy = TestXmlSerializer(item); - CheckCachedItem(item, copy); } [Test] @@ -105,9 +94,6 @@ public void TestCacheLockSerialization() copy = TestBinaryFormatter(item); CheckCacheLock(item, copy); - - copy = TestXmlSerializer(item); - CheckCacheLock(item, copy); } [Test] @@ -119,9 +105,6 @@ public void TestAnyTypeObjectTypeCacheEntrySerialization() copy = TestBinaryFormatter(item); CheckObjectTypeCacheEntry(item, copy); - - copy = TestXmlSerializer(item); - CheckObjectTypeCacheEntry(item, copy); } @@ -141,26 +124,26 @@ private CachedItem CreateCachedItem(object value) }; } - private CacheEntry CreateCacheEntry(Func, bool> predicate) + private CacheEntry CreateCacheEntry() { return new CacheEntry { - DisassembledState = GetAllKnownTypeValues(predicate), + DisassembledState = GetAllKnownTypeValues(), Version = 55, Subclass = "Test", AreLazyPropertiesUnfetched = true }; } - private CollectionCacheEntry CreateCollectionCacheEntry(Func, bool> predicate) + private CollectionCacheEntry CreateCollectionCacheEntry() { return new CollectionCacheEntry { - DisassembledState = GetAllKnownTypeValues(predicate) + DisassembledState = GetAllKnownTypeValues() }; } - private object[] GetAllKnownTypeValues(Func, bool> predicate) + private object[] GetAllKnownTypeValues() { var entityName = nameof(MyEntity); var xmlDoc = new XmlDocument(); @@ -212,10 +195,6 @@ private object[] GetAllKnownTypeValues(Func, bool> p {NHibernateUtil.XDoc, XDocument.Parse("XDoc")}, {NHibernateUtil.Uri, new Uri("http://test.com")} }; - if (predicate != null) - { - types = types.Where(predicate).ToDictionary(o => o.Key, o => o.Value); - } var sessionImpl = Substitute.For(); sessionImpl.BestGuessEntityName(Arg.Any()).Returns(o => o[0].GetType().Name); @@ -332,14 +311,6 @@ private static T TestDataContractSerializer(T obj) return obj; } - private static T TestXmlSerializer(T obj) - { - var xml = XmlSerializerToXml(obj); - obj = XmlSerializerFromXml(xml); - Assert.That(xml, Is.EqualTo(XmlSerializerToXml(obj))); - return obj; - } - private static T TestBinaryFormatter(T obj) { var bytes = BinaryFormatterToBinary(obj); @@ -353,8 +324,7 @@ private static string DataContractSerializerToXml(T obj) using (var memoryStream = new MemoryStream()) using (var reader = new StreamReader(memoryStream)) { - - var serializer = new DataContractSerializer(typeof(T)); + var serializer = new DataContractSerializer(typeof(T), KnownTypes); serializer.WriteObject(memoryStream, obj); memoryStream.Position = 0; return reader.ReadToEnd(); @@ -368,30 +338,11 @@ private static T DataContractSerializerFromXml(string xml) var data = Encoding.UTF8.GetBytes(xml); stream.Write(data, 0, data.Length); stream.Position = 0; - var deserializer = new DataContractSerializer(typeof(T)); + var deserializer = new DataContractSerializer(typeof(T), KnownTypes); return (T) deserializer.ReadObject(stream); } } - private static string XmlSerializerToXml(T obj) - { - var serializer = new XmlSerializer(typeof(T)); - using (var writer = new StringWriter()) - { - serializer.Serialize(writer, obj); - return writer.ToString(); - } - } - - private static T XmlSerializerFromXml(string xml) - { - var serializer = new XmlSerializer(typeof(T)); - using (var reader = new StringReader(xml)) - { - return (T) serializer.Deserialize(reader); - } - } - private static byte[] BinaryFormatterToBinary(T obj) { var serializer = new BinaryFormatter(); diff --git a/src/NHibernate/Async/Cache/Entry/CacheEntry.cs b/src/NHibernate/Async/Cache/Entry/CacheEntry.cs index 42201158558..c59b8976e9c 100644 --- a/src/NHibernate/Async/Cache/Entry/CacheEntry.cs +++ b/src/NHibernate/Async/Cache/Entry/CacheEntry.cs @@ -10,12 +10,9 @@ using System; using System.Runtime.Serialization; -using System.Xml.Serialization; using NHibernate.Engine; using NHibernate.Event; -using NHibernate.Intercept; using NHibernate.Persister.Entity; -using NHibernate.Properties; using NHibernate.Type; namespace NHibernate.Cache.Entry diff --git a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs index 7a553c37ab3..18abd80f444 100644 --- a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs @@ -10,12 +10,8 @@ using System; using System.Runtime.Serialization; -using System.Xml.Serialization; using NHibernate.Collection; -using NHibernate.Intercept; using NHibernate.Persister.Collection; -using NHibernate.Properties; -using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Cache.Entry diff --git a/src/NHibernate/Async/Cache/ReadWriteCache.cs b/src/NHibernate/Async/Cache/ReadWriteCache.cs index 4e1bb8c40b3..3a307c975fe 100644 --- a/src/NHibernate/Async/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Async/Cache/ReadWriteCache.cs @@ -226,7 +226,7 @@ async Task InternalPutManyAsync() lockable.IsPuttable(timestamp, version, versionComparers[i]); if (puttable) { - putBatch.Add(key, new CachedItem(values[i], cache.NextTimestamp(), version)); + putBatch.Add(key, CachedItem.Create(values[i], cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); diff --git a/src/NHibernate/Cache/CachedItem.cs b/src/NHibernate/Cache/CachedItem.cs index b92e45c66a3..279aa4fd5ce 100644 --- a/src/NHibernate/Cache/CachedItem.cs +++ b/src/NHibernate/Cache/CachedItem.cs @@ -1,8 +1,6 @@ using System; using System.Collections; using System.Runtime.Serialization; -using System.Xml.Serialization; -using NHibernate.Cache.Entry; namespace NHibernate.Cache { @@ -11,11 +9,7 @@ namespace NHibernate.Cache /// when it was unlocked /// [Serializable] - [XmlInclude(typeof(CacheEntry))] - [XmlInclude(typeof(CollectionCacheEntry))] [DataContract] - [KnownType(typeof(CacheEntry))] - [KnownType(typeof(CollectionCacheEntry))] public class CachedItem : ReadWriteCache.ILockable { private long freshTimestamp; diff --git a/src/NHibernate/Cache/Entry/CacheEntry.cs b/src/NHibernate/Cache/Entry/CacheEntry.cs index 8580f3496b3..01f7f728a6e 100644 --- a/src/NHibernate/Cache/Entry/CacheEntry.cs +++ b/src/NHibernate/Cache/Entry/CacheEntry.cs @@ -1,11 +1,8 @@ using System; using System.Runtime.Serialization; -using System.Xml.Serialization; using NHibernate.Engine; using NHibernate.Event; -using NHibernate.Intercept; using NHibernate.Persister.Entity; -using NHibernate.Properties; using NHibernate.Type; namespace NHibernate.Cache.Entry @@ -14,15 +11,7 @@ namespace NHibernate.Cache.Entry /// A cached instance of a persistent class /// [Serializable] - [XmlInclude(typeof(AnyType.ObjectTypeCacheEntry))] - [XmlInclude(typeof(UnfetchedLazyProperty))] - [XmlInclude(typeof(UnknownBackrefProperty))] [DataContract] - [KnownType(typeof(AnyType.ObjectTypeCacheEntry))] - [KnownType(typeof(DateTimeOffset))] - [KnownType(typeof(TimeSpan))] - [KnownType(typeof(UnfetchedLazyProperty))] - [KnownType(typeof(UnknownBackrefProperty))] public sealed partial class CacheEntry { private object[] disassembledState; diff --git a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs index 182a3e8db02..6b149ae0024 100644 --- a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs @@ -1,27 +1,13 @@ using System; using System.Runtime.Serialization; -using System.Xml.Serialization; using NHibernate.Collection; -using NHibernate.Intercept; using NHibernate.Persister.Collection; -using NHibernate.Properties; -using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Cache.Entry { [Serializable] - [XmlInclude(typeof(AnyType.ObjectTypeCacheEntry))] - [XmlInclude(typeof(object[]))] - [XmlInclude(typeof(UnfetchedLazyProperty))] - [XmlInclude(typeof(UnknownBackrefProperty))] [DataContract] - [KnownType(typeof(AnyType.ObjectTypeCacheEntry))] - [KnownType(typeof(object[]))] - [KnownType(typeof(DateTimeOffset))] - [KnownType(typeof(TimeSpan))] - [KnownType(typeof(UnfetchedLazyProperty))] - [KnownType(typeof(UnknownBackrefProperty))] public partial class CollectionCacheEntry { private object state; diff --git a/src/NHibernate/Cache/ReadWriteCache.cs b/src/NHibernate/Cache/ReadWriteCache.cs index 462cc9ba4a2..92a08c47f01 100644 --- a/src/NHibernate/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Cache/ReadWriteCache.cs @@ -266,7 +266,7 @@ public bool[] PutMany(CacheKey[] keys, object[] values, long timestamp, object[] lockable.IsPuttable(timestamp, version, versionComparers[i]); if (puttable) { - putBatch.Add(key, new CachedItem(values[i], cache.NextTimestamp(), version)); + putBatch.Add(key, CachedItem.Create(values[i], cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); From d583df0e82188edf73b74bb64c4c9470d0570491 Mon Sep 17 00:00:00 2001 From: maca88 Date: Sun, 1 Jul 2018 13:29:44 +0200 Subject: [PATCH 3/3] Restored CollectionCacheEntry to use State property --- .../Async/CacheTest/SerializationFixture.cs | 9 ++++---- .../CacheTest/SerializationFixture.cs | 9 ++++---- .../Async/Cache/Entry/CollectionCacheEntry.cs | 4 ++-- .../Cache/Entry/CollectionCacheEntry.cs | 21 ++++++------------- .../Entry/StructuredCollectionCacheEntry.cs | 4 ++-- .../Cache/Entry/StructuredMapCacheEntry.cs | 4 ++-- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs index b48bc6ba908..274dc727bbf 100644 --- a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs @@ -43,6 +43,7 @@ public class SerializationFixtureAsync typeof(object[]), typeof(CacheEntry), typeof(CacheLock), + typeof(CachedItem), typeof(CollectionCacheEntry) }; @@ -150,7 +151,7 @@ private CollectionCacheEntry CreateCollectionCacheEntry() { return new CollectionCacheEntry { - DisassembledState = GetAllKnownTypeValues() + State = GetAllKnownTypeValues() }; } @@ -277,10 +278,10 @@ private void CheckCachedItem(CachedItem original, CachedItem copy) private void CheckCollectionCacheEntry(CollectionCacheEntry original, CollectionCacheEntry copy) { - Assert.That(copy.DisassembledState, Is.TypeOf(original.DisassembledState.GetType())); + Assert.That(copy.State, Is.TypeOf(original.State.GetType())); - var originalArray = (object[]) original.DisassembledState; - var copyArray = (object[]) copy.DisassembledState; + var originalArray = original.State; + var copyArray = copy.State; for (var i = 0; i < copyArray.Length; i++) { diff --git a/src/NHibernate.Test/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/CacheTest/SerializationFixture.cs index 82abb428a36..e133678fe65 100644 --- a/src/NHibernate.Test/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/CacheTest/SerializationFixture.cs @@ -32,6 +32,7 @@ public class SerializationFixture typeof(object[]), typeof(CacheEntry), typeof(CacheLock), + typeof(CachedItem), typeof(CollectionCacheEntry) }; @@ -139,7 +140,7 @@ private CollectionCacheEntry CreateCollectionCacheEntry() { return new CollectionCacheEntry { - DisassembledState = GetAllKnownTypeValues() + State = GetAllKnownTypeValues() }; } @@ -266,10 +267,10 @@ private void CheckCachedItem(CachedItem original, CachedItem copy) private void CheckCollectionCacheEntry(CollectionCacheEntry original, CollectionCacheEntry copy) { - Assert.That(copy.DisassembledState, Is.TypeOf(original.DisassembledState.GetType())); + Assert.That(copy.State, Is.TypeOf(original.State.GetType())); - var originalArray = (object[]) original.DisassembledState; - var copyArray = (object[]) copy.DisassembledState; + var originalArray = original.State; + var copyArray = copy.State; for (var i = 0; i < copyArray.Length; i++) { diff --git a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs index 18abd80f444..6072be6a15e 100644 --- a/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Async/Cache/Entry/CollectionCacheEntry.cs @@ -26,14 +26,14 @@ public static async Task CreateAsync(IPersistentCollection cancellationToken.ThrowIfCancellationRequested(); return new CollectionCacheEntry { - DisassembledState = await (collection.DisassembleAsync(persister, cancellationToken)).ConfigureAwait(false) + state = await (collection.DisassembleAsync(persister, cancellationToken)).ConfigureAwait(false) }; } public virtual async Task AssembleAsync(IPersistentCollection collection, ICollectionPersister persister, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - await (collection.InitializeFromCacheAsync(persister, DisassembledState, owner, cancellationToken)).ConfigureAwait(false); + await (collection.InitializeFromCacheAsync(persister, state, owner, cancellationToken)).ConfigureAwait(false); collection.AfterInitialize(persister); } } diff --git a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs index 6b149ae0024..7d5aeba52ec 100644 --- a/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/CollectionCacheEntry.cs @@ -20,43 +20,34 @@ public CollectionCacheEntry() [Obsolete("Use CollectionCacheEntry.Create method instead.")] public CollectionCacheEntry(IPersistentCollection collection, ICollectionPersister persister) { - DisassembledState = collection.Disassemble(persister); + state = collection.Disassemble(persister); } public static CollectionCacheEntry Create(IPersistentCollection collection, ICollectionPersister persister) { return new CollectionCacheEntry { - DisassembledState = collection.Disassemble(persister) + state = collection.Disassemble(persister) }; } // 6.0 TODO convert to auto-property [DataMember] - public object DisassembledState + public virtual object[] State { - get => state; + get => (object[]) state; //TODO: assumes all collections disassemble to an array! set => state = value; } - //TODO: assumes all collections disassemble to an array! - [Obsolete("Please use DisassembledState property instead.")] - public virtual object[] State => (object[]) DisassembledState; - public virtual void Assemble(IPersistentCollection collection, ICollectionPersister persister, object owner) { - collection.InitializeFromCache(persister, DisassembledState, owner); + collection.InitializeFromCache(persister, state, owner); collection.AfterInitialize(persister); } public override string ToString() { - if (DisassembledState is object[] array) - { - return "CollectionCacheEntry" + ArrayHelper.ToString(array); - } - return "CollectionCacheEntry" + StringHelper.Unqualify(DisassembledState.GetType().FullName) + "@" + - DisassembledState.GetHashCode(); + return "CollectionCacheEntry" + ArrayHelper.ToString(State); } } } diff --git a/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs b/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs index f4b57fde4b1..13a63af6719 100644 --- a/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/StructuredCollectionCacheEntry.cs @@ -11,7 +11,7 @@ public class StructuredCollectionCacheEntry : ICacheEntryStructure public virtual object Structure(object item) { var entry = (CollectionCacheEntry)item; - return new List((object[])entry.DisassembledState); + return new List(entry.State); } public virtual object Destructure(object item, ISessionFactoryImplementor factory) @@ -20,7 +20,7 @@ public virtual object Destructure(object item, ISessionFactoryImplementor factor var objects = collection != null ? collection.Cast().ToArray() : Array.Empty(); - return new CollectionCacheEntry {DisassembledState = objects}; + return new CollectionCacheEntry {State = objects}; } } } diff --git a/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs b/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs index decc60f1d24..8e1936450d7 100644 --- a/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs +++ b/src/NHibernate/Cache/Entry/StructuredMapCacheEntry.cs @@ -8,7 +8,7 @@ public class StructuredMapCacheEntry : ICacheEntryStructure public object Structure(object item) { CollectionCacheEntry entry = (CollectionCacheEntry)item; - object[] state = (object[])entry.DisassembledState; + object[] state = entry.State; IDictionary map = new Hashtable(state.Length); for (int i = 0; i < state.Length; ) { @@ -27,7 +27,7 @@ public object Destructure(object item, ISessionFactoryImplementor factory) state[i++] = me.Key; state[i++] = me.Value; } - return new CollectionCacheEntry {DisassembledState = state}; + return new CollectionCacheEntry {State = state}; } } }