1. Roger Kratz
  2. NHibernate.Envers

Commits

Roger Kratz  committed f117181

Fixing NHE-96

Involves some ugly reflection in IdBagCollectionMapper
-> fix if NH Core makes it possible

  • Participants
  • Parent commits 62dac5a
  • Branches default

Comments (0)

Files changed (9)

File Src/NHibernate.Envers.Tests/NHibernate.Envers.Tests.csproj

View file
  • Ignore whitespace
     <Compile Include="NetSpecific\Integration\DynamicComponent\JoinWithDynamicComponent\Person.cs" />
     <Compile Include="NetSpecific\Integration\EnumType\CustomEnumTypeTest.cs" />
     <Compile Include="NetSpecific\Integration\EnumType\Model.cs" />
+    <Compile Include="NetSpecific\Integration\IdBag\ManyToMany\UniDirectional\Fixture.cs" />
+    <Compile Include="NetSpecific\Integration\IdBag\ManyToMany\UniDirectional\UniOwned.cs" />
+    <Compile Include="NetSpecific\Integration\IdBag\ManyToMany\UniDirectional\UniOwning.cs" />
     <Compile Include="NetSpecific\Integration\OneToMany\Child.cs" />
     <Compile Include="NetSpecific\Integration\OneToMany\Parent.cs" />
     <Compile Include="NetSpecific\Integration\OneToMany\UniDirectionalWithBackRefTest.cs" />
     <Compile Include="ValidityTestBase.cs" />
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="NetSpecific\Integration\IdBag\ManyToMany\UniDirectional\Mapping.hbm.xml" />
     <EmbeddedResource Include="NetSpecific\Integration\EnumType\Mapping.hbm.xml" />
     <EmbeddedResource Include="NetSpecific\Integration\OneToMany\Mapping.hbm.xml" />
     <EmbeddedResource Include="NetSpecific\UnitTests\Ids\Mapping.hbm.xml" />

File Src/NHibernate.Envers.Tests/NetSpecific/Integration/IdBag/ManyToMany/UniDirectional/Fixture.cs

View file
  • Ignore whitespace
+using System;
+using System.Linq;
+using NUnit.Framework;
+using SharpTestsEx;
+
+namespace NHibernate.Envers.Tests.NetSpecific.Integration.IdBag.ManyToMany.UniDirectional
+{
+	[TestFixture]
+	public class Fixture : TestBase
+	{
+		private Guid owningId1;
+		private Guid owningId2;
+		private Guid ownedId1;
+		private Guid ownedId2;
+
+		public Fixture(string strategyType)
+			: base(strategyType)
+		{
+		}
+
+		protected override void Initialize()
+		{
+			var owning1 = new UniOwning();
+			var owning2 = new UniOwning();
+			using (var tx = Session.BeginTransaction())
+			{
+				Session.Save(owning1);
+				Session.Save(owning2);
+				tx.Commit();
+			}
+			var owned1 = new UniOwned { Number = 1 };
+			var owned2 = new UniOwned { Number = 2 };
+			using (var tx = Session.BeginTransaction())
+			{
+				owning1.Referencing.Add(owned1);
+				owning1.Referencing.Add(owned2);
+				owning2.Referencing.Add(owned1);
+				tx.Commit();
+			}
+			using (var tx = Session.BeginTransaction())
+			{
+				owning1.Referencing.Remove(owned1);
+				tx.Commit();
+			}
+			owningId1 = owning1.Id;
+			owningId2 = owning2.Id;
+			ownedId1 = owned1.Id;
+			ownedId2 = owned2.Id;
+		}
+
+		[Test]
+		public void VerifyRevisionsCounts()
+		{
+			AuditReader().GetRevisions(typeof(UniOwning), owningId1)
+				.Should().Have.SameSequenceAs(1, 2, 3);
+			AuditReader().GetRevisions(typeof(UniOwning), owningId2)
+				.Should().Have.SameSequenceAs(1, 2);
+
+			AuditReader().GetRevisions(typeof(UniOwned), ownedId1)
+				.Should().Have.SameSequenceAs(2);
+			AuditReader().GetRevisions(typeof(UniOwned), ownedId2)
+				.Should().Have.SameSequenceAs(2);
+		}
+
+		[Test]
+		public void VerifyHistoryOfOwning1()
+		{
+			var owned1 = new UniOwned { Id = ownedId1, Number = 1 };
+			var owned2 = new UniOwned { Id = ownedId2, Number = 2 };
+
+			AuditReader().Find<UniOwning>(owningId1, 1)
+				.Referencing.Should().Be.Empty();
+			AuditReader().Find<UniOwning>(owningId1, 2)
+				.Referencing.Should().Have.SameValuesAs(owned1, owned2);
+			AuditReader().Find<UniOwning>(owningId1, 3)
+				.Referencing.Should().Have.SameValuesAs(owned2);
+		}
+
+		[Test]
+		public void VerifyHistoryOfOwning2()
+		{
+			var owned1 = new UniOwned { Id = ownedId1, Number = 1 };
+
+			AuditReader().Find<UniOwning>(owningId2, 1)
+				.Referencing.Should().Be.Empty();
+			AuditReader().Find<UniOwning>(owningId2, 2)
+				.Referencing.Should().Have.SameValuesAs(owned1);
+		}
+
+
+		[Test]
+		public void CanReuseAsNormalEntity()
+		{
+			using (var tx = Session.BeginTransaction())
+			{
+				var ver3 = AuditReader().Find<UniOwning>(owningId1, 3);
+				ver3.Referencing.First().Number = 5;
+				Session.Merge(ver3);
+				tx.Commit();
+			}
+			using (Session.BeginTransaction())
+			{
+				Session.Get<UniOwned>(ownedId2).Number.Should().Be.EqualTo(5);
+			}
+		}
+	}
+}

File Src/NHibernate.Envers.Tests/NetSpecific/Integration/IdBag/ManyToMany/UniDirectional/Mapping.hbm.xml

View file
  • Ignore whitespace
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+			assembly="NHibernate.Envers.Tests"
+			namespace="NHibernate.Envers.Tests.NetSpecific.Integration.IdBag.ManyToMany.UniDirectional">
+	<class name="UniOwning">
+		<id name="Id">
+			<generator class="guid.comb"/>
+		</id>
+		<idbag name="Referencing" cascade="all">
+			<collection-id column="theid" type="guid">
+				<generator class="guid.comb"/>
+			</collection-id>
+			<key column="owning"/>
+			<many-to-many class="UniOwned" column="owned"/>
+		</idbag>
+	</class>
+	<class name="UniOwned">
+		<id name="Id">
+			<generator class="guid.comb"/>
+		</id>
+		<property name="Number"/>
+	</class>
+</hibernate-mapping>

File Src/NHibernate.Envers.Tests/NetSpecific/Integration/IdBag/ManyToMany/UniDirectional/UniOwned.cs

View file
  • Ignore whitespace
+using System;
+using NHibernate.Envers.Configuration.Attributes;
+
+namespace NHibernate.Envers.Tests.NetSpecific.Integration.IdBag.ManyToMany.UniDirectional
+{
+	[Audited]
+	public class UniOwned
+	{
+		public virtual Guid Id { get; set; }
+		public virtual int Number { get; set; }
+
+		public override bool Equals(object obj)
+		{
+			var that = obj as UniOwned;
+			if (that == null)
+				return false;
+			return Id == that.Id && Number == that.Number;
+		}
+
+		public override int GetHashCode()
+		{
+			return Id.GetHashCode() ^ Number;
+		}
+	}
+}

File Src/NHibernate.Envers.Tests/NetSpecific/Integration/IdBag/ManyToMany/UniDirectional/UniOwning.cs

View file
  • Ignore whitespace
+using System;
+using System.Collections.Generic;
+using NHibernate.Envers.Configuration.Attributes;
+
+namespace NHibernate.Envers.Tests.NetSpecific.Integration.IdBag.ManyToMany.UniDirectional
+{
+	[Audited]
+	public class UniOwning
+	{
+		public UniOwning()
+		{
+			Referencing = new List<UniOwned>();
+		}
+
+		public virtual Guid Id { get; set; }
+		public virtual ICollection<UniOwned> Referencing { get; set; }
+	}
+}

File Src/NHibernate.Envers/Configuration/Metadata/CollectionMetadataGenerator.cs

View file
  • Ignore whitespace
 					collectionMapper = collectionProxyMapperFactory.Bag(_mainGenerator.GlobalCfg.EnversProxyFactory, commonCollectionMapperData, elementComponentData);
 				}
 			}
+			else if (type is IdentifierBagType)
+			{
+				if (_propertyValue.IsGeneric)
+				{
+					var methodInfo = ReflectHelper.GetGenericMethodFrom<ICollectionMapperFactory>("IdBag",
+						type.ReturnedClass.GetGenericArguments(),
+						new[] { typeof(IEnversProxyFactory), typeof(CommonCollectionMapperData), typeof(MiddleComponentData), typeof(MiddleComponentData) });
+					collectionMapper = (IPropertyMapper)methodInfo.Invoke(collectionProxyMapperFactory,
+						new object[] { _mainGenerator.GlobalCfg.EnversProxyFactory, commonCollectionMapperData, elementComponentData, indexComponentData });
+				}
+				else
+				{
+					collectionMapper = collectionProxyMapperFactory.IdBag(_mainGenerator.GlobalCfg.EnversProxyFactory, commonCollectionMapperData, elementComponentData, indexComponentData);
+				}
+			}
 			else
 			{
 				if (type is CustomCollectionType)

File Src/NHibernate.Envers/Configuration/Metadata/DefaultCollectionMapperFactory.cs

View file
  • Ignore whitespace
 
 		public virtual IPropertyMapper IdBag<T>(IEnversProxyFactory enversProxyFactory, CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData, MiddleComponentData indexComponentData)
 		{
-			throw new NotImplementedException("Generic idbag is not supported by DefaultCollectionMapperFactory");
+			return new IdBagCollectionMapper<T>(enversProxyFactory, commonCollectionMapperData, typeof(IList<T>), elementComponentData);
 		}
 
 		public virtual IPropertyMapper IdBag(IEnversProxyFactory enversProxyFactory, CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData, MiddleComponentData indexComponentData)

File Src/NHibernate.Envers/Entities/Mapper/Relation/IdBagCollectionMapper.cs

View file
  • Ignore whitespace
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace NHibernate.Envers.Entities.Mapper.Relation
+{
+	[Serializable]
+	public class IdBagCollectionMapper<T> : BagCollectionMapper<T>
+	{
+		public IdBagCollectionMapper(IEnversProxyFactory enversProxyFactory,
+		                             CommonCollectionMapperData commonCollectionMapperData,
+		                             System.Type proxyType,
+		                             MiddleComponentData elementComponentData)
+			: base(enversProxyFactory, commonCollectionMapperData, proxyType, elementComponentData)
+		{
+		}
+
+		protected override IEnumerable GetOldCollectionContent(object oldCollection)
+		{
+			if (oldCollection == null)
+			{
+				return null;
+			}
+			var ret = new List<object>();
+			foreach (var item in (IEnumerable) oldCollection)
+			{
+				//hack - can't get the snapshot value without reflection. Needs to be changed inside NH Core
+				var itemValue = item.GetType().GetProperty("Value").GetValue(item, null);
+				ret.Add(itemValue);
+			}
+			return ret;
+		}
+	}
+}

File Src/NHibernate.Envers/NHibernate.Envers.csproj

View file
  • Ignore whitespace
     <Compile Include="Entities\Mapper\Relation\AbstractCollectionMapper.cs" />
     <Compile Include="Entities\Mapper\Relation\AbstractOneToOneMapper.cs" />
     <Compile Include="Entities\Mapper\Relation\AbstractToOneMapper.cs" />
+    <Compile Include="Entities\Mapper\Relation\IdBagCollectionMapper.cs" />
     <Compile Include="Entities\Mapper\Relation\IEnversProxyFactory.cs" />
     <Compile Include="Entities\Mapper\Relation\Lazy\Initializor\SortedMapCollectionInitializor.cs" />
     <Compile Include="Entities\Mapper\Relation\Lazy\Initializor\SortedSetCollectionInitializor.cs" />