Roger Kratz avatar Roger Kratz committed 487b24b

NHE-94 fixed

Comments (0)

Files changed (10)

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/Item.cs

+using NHibernate.Envers.Configuration.Attributes;
+
+namespace NHibernate.Envers.Tests.Integration.Ids.EmbeddedId
+{
+	[Audited]
+	public class Item
+	{
+		public virtual ItemId Id { get; set; }
+		public virtual double Price { get; set; }
+
+		public override bool Equals(object obj)
+		{
+			var item = obj as Item;
+			if (item == null)
+				return false;
+			if (Id != null ? !Id.Equals(item.Id) : item.Id != null)
+				return false;
+			if (Price != item.Price)
+				return false;
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			var result = Id != null ? Id.GetHashCode() : 0;
+			result = 31*result + Price.GetHashCode();
+			return result;
+		}
+	}
+}

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/ItemId.cs

+namespace NHibernate.Envers.Tests.Integration.Ids.EmbeddedId
+{
+	public class ItemId
+	{
+		public virtual string Model { get; set; }
+		public virtual int Version { get; set; }
+		public virtual Producer Producer { get; set; }
+
+		public override bool Equals(object obj)
+		{
+			var itemId = obj as ItemId;
+			if (itemId == null)
+				return false;
+			if (Model != null ? !Model.Equals(itemId.Model) : itemId.Model != null) 
+				return false;
+			if (Producer != null ? !Producer.Equals(itemId.Producer) : itemId.Producer != null) 
+				return false;
+			if (Version != itemId.Version)
+				return false;
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			var res = Model != null ? Model.GetHashCode() : 0;
+			res = 31*res + Version.GetHashCode();
+			res = 31*res + (Producer != null ? Producer.GetHashCode() : 0);
+			return res;
+		}
+	}
+}

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/Mapping.hbm.xml

+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+	 assembly="NHibernate.Envers.Tests"
+	 namespace="NHibernate.Envers.Tests.Integration.Ids.EmbeddedId">
+	<class name="PurchaseOrder">
+		<id name="Id">
+			<generator class="identity"/>
+		</id>
+		<property name="Comment" column="note" />
+		<many-to-one name="Item">
+			<column name="Model" />
+			<column name="Version" />
+			<column name="Producer" />
+		</many-to-one>
+	</class>
+
+	<class name="Producer">
+		<id name="Id">
+			<generator class="assigned"/>
+		</id>
+		<property name="Name"/>
+	</class>
+
+	<class name="Item">
+		<composite-id class="ItemId" name="Id">
+			<key-property name="Model"/>
+			<key-property name="Version" />
+			<key-many-to-one name="Producer"/>
+		</composite-id>
+		<property name="Price"/>
+	</class>
+</hibernate-mapping>

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/Producer.cs

+using NHibernate.Envers.Configuration.Attributes;
+
+namespace NHibernate.Envers.Tests.Integration.Ids.EmbeddedId
+{
+	[Audited]
+	public class Producer
+	{
+		public virtual int Id { get; set; }
+		public virtual string Name { get; set; }
+
+		public override bool Equals(object obj)
+		{
+			var producer = obj as Producer;
+			if (producer == null)
+				return false;
+			if (Id != producer.Id)
+				return false;
+			if (Name != null ? !Name.Equals(producer.Name) : producer.Name != null) 
+				return false;
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			var result = Id.GetHashCode();
+			result = 31*result + (Name != null ? Name.GetHashCode() : 0);
+			return result;
+		}
+	}
+}

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/PurchaseOrder.cs

+using NHibernate.Envers.Configuration.Attributes;
+
+namespace NHibernate.Envers.Tests.Integration.Ids.EmbeddedId
+{
+	[Audited]
+	public class PurchaseOrder
+	{
+		public virtual int Id { get; set; }
+		public virtual Item Item { get; set; }
+		public virtual string Comment { get; set; }
+
+		public override bool Equals(object obj)
+		{
+			var that = obj as PurchaseOrder;
+			if (that == null)
+				return false;
+			if (Comment != null ? !Comment.Equals(that.Comment) : that.Comment != null) 
+				return false;
+			if (Item != null ? !Item.Equals(that.Item) : that.Item != null) 
+				return false;
+			if (Id != that.Id)
+				return false;
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			var result = Id;
+			result = 31 * result + (Item != null ? Item.GetHashCode() : 0);
+			result = 31 * result + (Comment != null ? Comment.GetHashCode() : 0);
+			return result;
+		}
+	}
+}

Src/NHibernate.Envers.Tests/Integration/Ids/EmbeddedId/RelationInsideEmbeddableTest.cs

+using NUnit.Framework;
+using SharpTestsEx;
+
+namespace NHibernate.Envers.Tests.Integration.Ids.EmbeddedId
+{
+	public class RelationInsideEmbeddableTest : TestBase
+	{
+		private int orderId;
+		private ItemId itemId;
+
+		public RelationInsideEmbeddableTest(string strategyType) : base(strategyType)
+		{
+		}
+
+		protected override void Initialize()
+		{
+			var producer = new Producer {Id = 1, Name = "Sony"};
+			itemId = new ItemId {Model = "TV", Producer = producer, Version = 1};
+			var item = new Item {Id = itemId, Price = 100.5};
+			var order = new PurchaseOrder {Item = item};
+
+			//rev 1
+			using (var tx = Session.BeginTransaction())
+			{
+				Session.Save(producer);
+				Session.Save(item);
+				orderId = (int) Session.Save(order);
+				tx.Commit();
+			}
+
+			//rev 2
+			using (var tx = Session.BeginTransaction())
+			{
+				order.Comment = "fragile";
+				tx.Commit();
+			}
+
+			//rev 3
+			using (var tx = Session.BeginTransaction())
+			{
+				item.Price = 110;
+				tx.Commit();
+			}
+		}
+
+		[Test]
+		public void VerifyRevisionsCount()
+		{
+			AuditReader().GetRevisions(typeof (PurchaseOrder), orderId)
+				.Should().Have.SameSequenceAs(1, 2);
+			AuditReader().GetRevisions(typeof (Item), itemId)
+				.Should().Have.SameSequenceAs(1, 3);
+		}
+
+		[Test]
+		public void VerifyHistoryOfPurchaseOrder()
+		{
+			var item = new Item
+			           	{
+			           		Id = new ItemId {Model = "TV", Producer = new Producer {Id = 1, Name = "Sony"}, Version = 1},
+			           		Price = 100.5
+			           	};
+			AuditReader().Find<PurchaseOrder>(orderId, 1)
+				.Should().Be.EqualTo(new PurchaseOrder {Id = orderId, Item = item});
+			AuditReader().Find<PurchaseOrder>(orderId, 2)
+				.Should().Be.EqualTo(new PurchaseOrder {Id = orderId, Item = item, Comment = "fragile"});
+		}
+
+		[Test]
+		public void VerifyHistoryOfItem()
+		{
+			AuditReader().Find<Item>(itemId, 1)
+				.Should().Be.EqualTo(new Item {Id = itemId, Price = 100.5});
+			AuditReader().Find<Item>(itemId, 3)
+				.Should().Be.EqualTo(new Item { Id = itemId, Price = 110 });
+		} 
+	}
+}

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

     <Compile Include="Integration\Basic\TransactionRollbackBehaviourTest.cs" />
     <Compile Include="Integration\Ids\CompositeDateIdTest.cs" />
     <Compile Include="Integration\Ids\DateIdTest.cs" />
+    <Compile Include="Integration\Ids\EmbeddedId\Item.cs" />
+    <Compile Include="Integration\Ids\EmbeddedId\ItemId.cs" />
+    <Compile Include="Integration\Ids\EmbeddedId\Producer.cs" />
+    <Compile Include="Integration\Ids\EmbeddedId\PurchaseOrder.cs" />
+    <Compile Include="Integration\Ids\EmbeddedId\RelationInsideEmbeddableTest.cs" />
     <Compile Include="Integration\Ids\ManyToOneIdNotAuditedTest.cs" />
     <Compile Include="Integration\ManyToMany\Ternary\IntTestPrivSeqEntity.cs" />
     <Compile Include="Integration\ManyToMany\Ternary\StrTestPrivSeqEntity.cs" />
     <EmbeddedResource Include="Integration\NotUpdatable\Mapping.hbm.xml" />
     <EmbeddedResource Include="Integration\Ids\ManyToOneIdNotAuditedTest.hbm.xml" />
     <EmbeddedResource Include="Integration\OneToMany\EmbeddedId\Mapping.hbm.xml" />
+    <EmbeddedResource Include="Integration\Ids\EmbeddedId\Mapping.hbm.xml" />
     <Content Include="log4net.xml">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>

Src/NHibernate.Envers/Configuration/Metadata/BasicMetadataGenerator.cs

 			{
 				var mappingType = type.GetType();
 				var userDefined = isUserDefined(mappingType);
-				if(userDefined)
+				if (userDefined)
+				{
 					addCustomValue(parent, propertyAuditingData, value, mapper, insertable, key, mappingType);
+				}
 				else
-					addSimpleValue(parent, propertyAuditingData, value, mapper, insertable, key);
+				{
+					addSimpleValue(parent, propertyAuditingData, value, mapper, insertable, key);					
+				}
 			}
 			else if (custType != null)
 			{
 				mapper.Add(propertyAuditingData.GetPropertyData());
 			}
 		}
+
+		public bool AddKeyManyToOne(XmlElement parent, PropertyAuditingData propertyAuditingData, IValue value, ISimpleMapperBuilder mapper)
+		{
+			var type = value.Type;
+			XmlElement element;
+			if (mapper == null)
+			{
+				element = MetadataTools.AddKeyManyToOne(parent, propertyAuditingData.Name, type.ReturnedClass.AssemblyQualifiedName);	
+			}
+			else
+			{
+				element = MetadataTools.AddManyToOne(parent, propertyAuditingData.Name, type.ReturnedClass.AssemblyQualifiedName, true, false);	
+			}
+			MetadataTools.AddColumns(element, value.ColumnIterator.OfType<Column>());
+			// A null mapper occurs when adding to composite-id element
+			if (mapper != null)
+			{
+				mapper.Add(propertyAuditingData.GetPropertyData());
+			}
+			return true;
+		}
 	}
 }

Src/NHibernate.Envers/Configuration/Metadata/IdMetadataGenerator.cs

 using NHibernate.Envers.Entities.Mapper;
 using NHibernate.Envers.Entities.Mapper.Id;
 using NHibernate.Mapping;
+using NHibernate.Type;
 
 namespace NHibernate.Envers.Configuration.Metadata
 {
 				{
 					if (!propertyType.IsMutable)
 					{
-						// Last but one parameter: ids are always insertable
-						_mainGenerator.BasicMetadataGenerator.AddBasic(parent,
-								getIdPersistentPropertyAuditingData(property),
-								property.Value, mapper, true, key);
+						if (propertyType is ManyToOneType)
+						{
+							_mainGenerator.BasicMetadataGenerator.AddKeyManyToOne(parent,
+									 getIdPersistentPropertyAuditingData(property),
+									 property.Value, mapper);
+						}
+						else
+						{
+							// Last but one parameter: ids are always insertable
+							_mainGenerator.BasicMetadataGenerator.AddBasic(parent,
+									getIdPersistentPropertyAuditingData(property),
+									property.Value, mapper, true, key);							
+						}
 					}
 					else
 					{

Src/NHibernate.Envers/Configuration/Metadata/MetadataTools.cs

 			return manyToOneMapping;
 		}
 
+		public static XmlElement AddKeyManyToOne(XmlElement parent, string name, string type)
+		{
+			var manyToOneMapping = parent.OwnerDocument.CreateElement("key-many-to-one");
+			parent.AppendChild(manyToOneMapping);
+			manyToOneMapping.SetAttribute("name", name);
+			manyToOneMapping.SetAttribute("class", type);
+			return manyToOneMapping;
+		}
+
 		private static void AddOrModifyAttribute(XmlElement parent, string name, string value)
 		{
 			parent.SetAttribute(name, value);
 				for (var i = nodeList.Count - 1; i >= 0; i--)
 				{
 					var property = (XmlElement)nodeList[i];
-					if ("property".Equals(property.Name))
+					var propertyName = property.Name;
+					if ("property".Equals(propertyName) || "many-to-one".Equals(propertyName))
 					{
 						var value = property.GetAttribute("name");
 						if (!string.IsNullOrEmpty(value))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.