|
From: <fab...@us...> - 2011-05-24 12:18:35
|
Revision: 5869
http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5869&view=rev
Author: fabiomaulo
Date: 2011-05-24 12:18:28 +0000 (Tue, 24 May 2011)
Log Message:
-----------
Fix NH-2728
Modified Paths:
--------------
trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs
trunk/nhibernate/src/NHibernate/Mapping/ByCode/IModelInspector.cs
trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CollectionElementRelation.cs
trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs
trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs
trunk/nhibernate/src/NHibernate/NHibernate.csproj
trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
Added Paths:
-----------
trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/ManyToAnyMapper.cs
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Cat.cs
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Dog.cs
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/IAnimal.cs
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/SampleTest.cs
trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Toy.cs
Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -66,6 +66,11 @@
return OneToManyRelations.Contains(member);
}
+ public bool IsManyToAny(MemberInfo member)
+ {
+ return ManyToAnyRelations.Contains(member);
+ }
+
public virtual bool IsAny(MemberInfo member)
{
return Any.Contains(member);
Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/IModelInspector.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IModelInspector.cs 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/IModelInspector.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -18,6 +18,8 @@
bool IsManyToOne(MemberInfo member);
bool IsManyToMany(MemberInfo member);
bool IsOneToMany(MemberInfo member);
+ bool IsManyToAny(MemberInfo member);
+
bool IsAny(MemberInfo member);
bool IsPersistentId(MemberInfo member);
Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CollectionElementRelation.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CollectionElementRelation.cs 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CollectionElementRelation.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -48,7 +48,9 @@
public void ManyToAny(System.Type idTypeOfMetaType, Action<IManyToAnyMapper> mapping)
{
- throw new NotImplementedException();
+ var hbm = new HbmManyToAny();
+ mapping(new ManyToAnyMapper(collectionElementType, idTypeOfMetaType, hbm, mapDoc));
+ elementRelationshipAssing(hbm);
}
#endregion
Added: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/ManyToAnyMapper.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/ManyToAnyMapper.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/ManyToAnyMapper.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Type;
+
+namespace NHibernate.Mapping.ByCode.Impl
+{
+ public class ManyToAnyMapper: IManyToAnyMapper
+ {
+ private const string DefaultIdColumnNameWhenNoProperty = "ReferencedId";
+ private const string DefaultMetaColumnNameWhenNoProperty = "ReferencedClass";
+ private readonly System.Type elementType;
+ private readonly System.Type foreignIdType;
+ private readonly ColumnMapper classColumnMapper;
+ private readonly ColumnMapper idColumnMapper;
+
+ private readonly HbmManyToAny manyToAny;
+ private readonly HbmMapping mapDoc;
+
+ public ManyToAnyMapper(System.Type elementType, System.Type foreignIdType, HbmManyToAny manyToAny, HbmMapping mapDoc)
+ {
+ if (elementType == null)
+ {
+ throw new ArgumentNullException("elementType");
+ }
+ if (foreignIdType == null)
+ {
+ throw new ArgumentNullException("foreignIdType");
+ }
+ if (manyToAny == null)
+ {
+ throw new ArgumentNullException("manyToAny");
+ }
+ this.elementType = elementType;
+ this.foreignIdType = foreignIdType;
+ this.manyToAny = manyToAny;
+ this.mapDoc = mapDoc;
+ this.manyToAny.idtype = this.foreignIdType.GetNhTypeName();
+ var idHbmColumn = new HbmColumn();
+ idColumnMapper = new ColumnMapper(idHbmColumn, DefaultIdColumnNameWhenNoProperty);
+ var classHbmColumn = new HbmColumn();
+ classColumnMapper = new ColumnMapper(classHbmColumn, DefaultMetaColumnNameWhenNoProperty);
+ manyToAny.column = new[] { classHbmColumn, idHbmColumn };
+ }
+
+ public void MetaType(IType metaType)
+ {
+ if (metaType != null)
+ {
+ CheckMetaTypeImmutability(metaType.Name);
+ manyToAny.metatype = metaType.Name;
+ }
+ }
+
+ public void MetaType<TMetaType>()
+ {
+ MetaType(typeof(TMetaType));
+ }
+
+ public void MetaType(System.Type metaType)
+ {
+ if (metaType != null)
+ {
+ string nhTypeName = metaType.GetNhTypeName();
+ CheckMetaTypeImmutability(nhTypeName);
+ manyToAny.metatype = nhTypeName;
+ }
+ }
+
+ public void IdType(IType idType)
+ {
+ if (idType != null)
+ {
+ CheckIdTypeImmutability(idType.Name);
+ manyToAny.idtype = idType.Name;
+ }
+ }
+
+ public void IdType<TIdType>()
+ {
+ IdType(typeof(TIdType));
+ }
+
+ public void IdType(System.Type idType)
+ {
+ if (idType != null)
+ {
+ string nhTypeName = idType.GetNhTypeName();
+ CheckIdTypeImmutability(nhTypeName);
+ manyToAny.idtype = nhTypeName;
+ }
+ }
+
+ public void Columns(Action<IColumnMapper> idColumnMapping, Action<IColumnMapper> classColumnMapping)
+ {
+ idColumnMapping(idColumnMapper);
+ classColumnMapping(classColumnMapper);
+ }
+
+ public void MetaValue(object value, System.Type entityType)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ if (entityType == null)
+ {
+ throw new ArgumentNullException("entityType");
+ }
+ if (value is System.Type)
+ {
+ throw new ArgumentOutOfRangeException("value", "System.Type is invalid meta-type (you don't need to set meta-values).");
+ }
+ if(!elementType.IsAssignableFrom(entityType))
+ {
+ throw new ArgumentOutOfRangeException("entityType", string.Format("A {0} is not assignable to the collection's elements which type is {1}", entityType, elementType));
+ }
+ System.Type metavalueType = value.GetType();
+ if (manyToAny.metavalue == null)
+ {
+ manyToAny.metavalue = new HbmMetaValue[0];
+ }
+ Dictionary<string, string> values = manyToAny.metavalue.ToDictionary(mv => mv.value, mv => mv.@class);
+ MetaType(metavalueType);
+ string newClassMetavalue = entityType.GetShortClassName(mapDoc);
+ string metavalueKey = value.ToString();
+ string existingClassMetavalue;
+ if (values.TryGetValue(metavalueKey, out existingClassMetavalue) && existingClassMetavalue != newClassMetavalue)
+ {
+ throw new ArgumentException(
+ string.Format(
+ "Can't set two different classes for same meta-value (meta-value='{0}' old-class:'{1}' new-class='{2}')",
+ metavalueKey, existingClassMetavalue, newClassMetavalue));
+ }
+ values[metavalueKey] = newClassMetavalue;
+ manyToAny.metavalue = values.Select(vd => new HbmMetaValue { value = vd.Key, @class = vd.Value }).ToArray();
+ }
+
+ private void CheckMetaTypeImmutability(string nhTypeName)
+ {
+ if (manyToAny.metavalue != null && manyToAny.metavalue.Length > 0 && manyToAny.metatype != nhTypeName)
+ {
+ throw new ArgumentException(string.Format("Can't change the meta-type (was '{0}' trying to change to '{1}')", manyToAny.metatype, nhTypeName));
+ }
+ }
+
+ private void CheckIdTypeImmutability(string nhTypeName)
+ {
+ if (manyToAny.metavalue != null && manyToAny.metavalue.Length > 0 && manyToAny.idtype != nhTypeName)
+ {
+ throw new ArgumentException(string.Format("Can't change the id-type after add meta-values (was '{0}' trying to change to '{1}')", manyToAny.idtype, nhTypeName));
+ }
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -1264,6 +1264,10 @@
{
return new ComponentRelationMapper(property, ownerType, collectionElementType, membersProvider, modelInspector, customizerHolder, this);
}
+ if (modelInspector.IsManyToAny(property))
+ {
+ return new ManyToAnyRelationMapper(propertyPath, customizerHolder, this);
+ }
return new ElementRelationMapper(propertyPath, customizerHolder, this);
}
@@ -1619,6 +1623,35 @@
#endregion
+ #region Nested type: ManyToAnyRelationMapper
+
+ private class ManyToAnyRelationMapper : ICollectionElementRelationMapper
+ {
+ private readonly ICustomizersHolder customizersHolder;
+ private readonly ModelMapper modelMapper;
+ private readonly PropertyPath propertyPath;
+
+ public ManyToAnyRelationMapper(PropertyPath propertyPath, ICustomizersHolder customizersHolder, ModelMapper modelMapper)
+ {
+ this.propertyPath = propertyPath;
+ this.customizersHolder = customizersHolder;
+ this.modelMapper = modelMapper;
+ }
+
+ #region Implementation of ICollectionElementRelationMapper
+
+ public void Map(ICollectionElementRelation relation)
+ {
+ relation.ManyToAny(typeof(int), x => customizersHolder.InvokeCustomizers(propertyPath, x));
+ }
+
+ public void MapCollectionProperties(ICollectionPropertiesMapper mapped) { }
+
+ #endregion
+ }
+
+ #endregion
+
#region Nested type: OneToManyRelationMapper
private class OneToManyRelationMapper : ICollectionElementRelationMapper
Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs
===================================================================
--- trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -78,6 +78,11 @@
return OneToManyRelations.Contains(member);
}
+ public bool IsManyToAny(MemberInfo member)
+ {
+ return ManyToAnyRelations.Contains(member);
+ }
+
public bool IsAny(MemberInfo member)
{
return Any.Contains(member);
@@ -173,6 +178,7 @@
private Func<MemberInfo, bool, bool> isDynamicComponent = (m, declared) => declared;
private Func<MemberInfo, bool, bool> isAny = (m, declared) => declared;
private Func<MemberInfo, bool, bool> isManyToMany = (m, declared) => declared;
+ private Func<MemberInfo, bool, bool> isManyToAny = (m, declared) => declared;
private Func<MemberInfo, bool, bool> isManyToOne;
private Func<MemberInfo, bool, bool> isMemberOfNaturalId = (m, declared) => declared;
private Func<MemberInfo, bool, bool> isOneToMany;
@@ -713,6 +719,12 @@
return isOneToMany(member, declaredResult);
}
+ bool IModelInspector.IsManyToAny(MemberInfo member)
+ {
+ bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsManyToAny(m));
+ return isManyToAny(member, declaredResult);
+ }
+
bool IModelInspector.IsAny(MemberInfo member)
{
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsAny(m));
@@ -910,6 +922,15 @@
isOneToMany = match;
}
+ public void IsManyToAny(Func<MemberInfo, bool, bool> match)
+ {
+ if (match == null)
+ {
+ return;
+ }
+ isManyToAny = match;
+ }
+
public void IsAny(Func<MemberInfo, bool, bool> match)
{
if (match == null)
Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-05-24 12:18:28 UTC (rev 5869)
@@ -311,6 +311,7 @@
<Compile Include="Mapping\ByCode\Impl\CustomizersImpl\DynamicComponentCustomizer.cs" />
<Compile Include="Mapping\ByCode\Impl\CustomizersImpl\ManyToAnyCustomizer.cs" />
<Compile Include="Mapping\ByCode\Impl\DynamicComponentMapper.cs" />
+ <Compile Include="Mapping\ByCode\Impl\ManyToAnyMapper.cs" />
<Compile Include="Mapping\ByCode\PropertyGeneration.cs" />
<Compile Include="Mapping\ByCode\PropertyToField.cs" />
<Compile Include="Mapping\ByCode\SimpleModelInspector.cs" />
Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Cat.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Cat.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Cat.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,11 @@
+using System;
+
+namespace NHibernate.Test.MappingByCode.IntegrationTests.NH2728
+{
+ public class Cat : IAnimal
+ {
+ public virtual int Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual DateTime Born { get; set; }
+ }
+}
\ No newline at end of file
Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Dog.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Dog.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Dog.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,10 @@
+
+namespace NHibernate.Test.MappingByCode.IntegrationTests.NH2728
+{
+ public class Dog : IAnimal
+ {
+ public virtual int Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual int Walks { get; set; }
+ }
+}
Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/IAnimal.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/IAnimal.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/IAnimal.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,9 @@
+
+namespace NHibernate.Test.MappingByCode.IntegrationTests.NH2728
+{
+ public interface IAnimal
+ {
+ int Id { get; set; }
+ string Name { get; set; }
+ }
+}
Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/SampleTest.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/SampleTest.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/SampleTest.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,111 @@
+using System;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+
+namespace NHibernate.Test.MappingByCode.IntegrationTests.NH2728
+{
+ [TestFixture]
+ public class SampleTest : TestCaseMappingByCode
+ {
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ConventionModelMapper();
+ // Working Example
+ //mapper.Class<Toy>(rc => rc.Set(x => x.Animals, cmap => { }, rel => rel.ManyToAny<int>(meta =>
+ // {
+ // meta.MetaValue(1, typeof (Cat));
+ // meta.MetaValue(2, typeof (Dog));
+ // })));
+
+ // User needs
+ mapper.Class<Toy>(rc => rc.Set(x => x.Animals, cmap =>
+ {
+ cmap.Table("Animals_Toys");
+ cmap.Key(km => km.Column("Cat_Id"));
+ }, rel => rel.ManyToAny<int>(meta =>
+ {
+ meta.MetaValue(1, typeof(Cat));
+ meta.MetaValue(2, typeof(Dog));
+ meta.Columns(cid =>
+ {
+ cid.Name("Animal_Id");
+ cid.NotNullable(true);
+ }, ctype =>
+ {
+ ctype.Name("Animal_Type");
+ ctype.NotNullable(true);
+ });
+ })));
+ var mappings = mapper.CompileMappingFor(new[] { typeof(Cat), typeof(Dog), typeof(Toy) });
+ //Console.WriteLine(mappings.AsString()); // <=== uncomment this line to see the XML mapping
+ return mappings;
+ }
+
+ protected override void OnSetUp()
+ {
+ base.OnSetUp();
+ using (ISession session = this.OpenSession())
+ {
+ var cat1 = new Cat()
+ {
+ Id = 1,
+ Name = "Cat 1",
+ Born = DateTime.Now,
+ };
+ session.Save(cat1);
+
+ var cat2 = new Cat()
+ {
+ Id = 2,
+ Name = "Cat 2",
+ Born = DateTime.Now,
+ };
+ session.Save(cat2);
+
+ var dog1 = new Dog()
+ {
+ Id = 1,
+ Name = "Dog 1",
+ Walks = 11,
+ };
+ session.Save(dog1);
+
+ var toy1 = new Toy()
+ {
+ Id = 1,
+ Name = "Toy 1",
+ };
+ toy1.Animals.Add(cat1);
+ toy1.Animals.Add(cat2);
+ toy1.Animals.Add(dog1);
+ session.Save(toy1);
+
+ session.Flush();
+ }
+ }
+
+ protected override void OnTearDown()
+ {
+ base.OnTearDown();
+ using (ISession session = this.OpenSession())
+ {
+ string hql = "from System.Object";
+ session.Delete(hql);
+ session.Flush();
+ }
+ }
+
+ [Test]
+ public void ShouldBeAbleToGetFromToyToAnimals()
+ {
+ using (ISession session = this.OpenSession())
+ {
+ var toy1 = session.Get<Toy>(1);
+
+ Assert.AreEqual(1, toy1.Id);
+ Assert.AreEqual(3, toy1.Animals.Count);
+ }
+ }
+ }
+}
Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Toy.cs
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Toy.cs (rev 0)
+++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/IntegrationTests/NH2728/Toy.cs 2011-05-24 12:18:28 UTC (rev 5869)
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace NHibernate.Test.MappingByCode.IntegrationTests.NH2728
+{
+ public class Toy
+ {
+ public Toy()
+ {
+ Animals = new HashSet<IAnimal>();
+ }
+
+ public virtual int Id { get; set; }
+ public virtual string Name { get; set; }
+
+ public virtual ICollection<IAnimal> Animals { get; protected set; }
+ }
+}
Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj
===================================================================
--- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-05-24 05:29:15 UTC (rev 5868)
+++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-05-24 12:18:28 UTC (rev 5869)
@@ -552,6 +552,11 @@
<Compile Include="MappingByCode\ExpliticMappingTests\SubclassPropertiesSplitsTests.cs" />
<Compile Include="MappingByCode\ExpliticMappingTests\VersionTests.cs" />
<Compile Include="MappingByCode\For.cs" />
+ <Compile Include="MappingByCode\IntegrationTests\NH2728\Cat.cs" />
+ <Compile Include="MappingByCode\IntegrationTests\NH2728\Dog.cs" />
+ <Compile Include="MappingByCode\IntegrationTests\NH2728\IAnimal.cs" />
+ <Compile Include="MappingByCode\IntegrationTests\NH2728\SampleTest.cs" />
+ <Compile Include="MappingByCode\IntegrationTests\NH2728\Toy.cs" />
<Compile Include="MappingByCode\MappersTests\AnyMapperTest.cs" />
<Compile Include="MappingByCode\MappersTests\IdMapperTest.cs" />
<Compile Include="MappingByCode\MappersTests\ManyToOneMapperTest.cs" />
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|