From: <fab...@us...> - 2008-09-29 22:46:41
|
Revision: 3807 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3807&view=rev Author: fabiomaulo Date: 2008-09-29 22:46:17 +0000 (Mon, 29 Sep 2008) Log Message: ----------- Fix NH-1173 new feature Generic Ordered Set support (by Sean Carpenter) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/Set.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Type/GenericOrderedSetType.cs trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/ trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/A.cs trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/B.cs trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.cs trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.hbm.xml Modified: trunk/nhibernate/src/NHibernate/Mapping/Set.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Set.cs 2008-09-29 22:14:24 UTC (rev 3806) +++ trunk/nhibernate/src/NHibernate/Mapping/Set.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -34,8 +34,7 @@ } else if (HasOrder) { - throw new MappingException( - "Cannot use order-by with generic set, no appropriate collection implementation is available"); + return TypeFactory.GenericOrderedSet(Role, ReferencedPropertyName, this.GenericArguments[0]); } else { Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-09-29 22:14:24 UTC (rev 3806) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-09-29 22:46:17 UTC (rev 3807) @@ -1062,6 +1062,7 @@ <Compile Include="Type\CollectionType.cs" /> <Compile Include="Type\CustomCollectionType.cs" /> <Compile Include="Type\EmbeddedComponentType.cs" /> + <Compile Include="Type\GenericOrderedSetType.cs" /> <Compile Include="Type\ICacheAssembler.cs" /> <Compile Include="Type\OrderedSetType.cs" /> <Compile Include="Type\OrderedMapType.cs" /> Added: trunk/nhibernate/src/NHibernate/Type/GenericOrderedSetType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/GenericOrderedSetType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Type/GenericOrderedSetType.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -0,0 +1,31 @@ +using System; +using Iesi.Collections.Generic; + +namespace NHibernate.Type +{ + /// <summary> + /// An <see cref="IType"/> that maps a sorted <see cref="ISet{T}"/> collection + /// to the database. + /// </summary> + [Serializable] + public class GenericOrderedSetType<T> : GenericSetType<T> + { + /// <summary> + /// Initializes a new instance of a <see cref="GenericOrderedSetType{T}"/> class for + /// a specific role. + /// </summary> + /// <param name="role">The role the persistent collection is in.</param> + /// <param name="propertyRef">The name of the property in the + /// owner object containing the collection ID, or <see langword="null" /> if it is + /// the primary key.</param> + public GenericOrderedSetType(string role, string propertyRef) + : base(role, propertyRef) + { + } + + public override object Instantiate(int anticipatedSize) + { + return new OrderedSet<T>(); + } + } +} Modified: trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-09-29 22:14:24 UTC (rev 3806) +++ trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -33,8 +33,8 @@ PrecisionScale } - private static readonly char[] precisionScaleSplit = new char[] {'(', ')', ','}; - private static readonly char[] lengthSplit = new char[] {'(', ')'}; + private static readonly char[] precisionScaleSplit = new char[] { '(', ')', ',' }; + private static readonly char[] lengthSplit = new char[] { '(', ')' }; /* * Maps the string representation of the type to the IType. The string @@ -59,7 +59,7 @@ private static readonly IDictionary<string, IType> typeByTypeOfName = new ThreadSafeDictionary<string, IType>(new Dictionary<string, IType>()); - private static readonly IDictionary<string, GetNullableTypeWithLength> getTypeDelegatesWithLength = + private static readonly IDictionary<string, GetNullableTypeWithLength> getTypeDelegatesWithLength = new ThreadSafeDictionary<string, GetNullableTypeWithLength>(new Dictionary<string, GetNullableTypeWithLength>()); private static readonly IDictionary<string, GetNullableTypeWithPrecision> getTypeDelegatesWithPrecision = @@ -241,7 +241,7 @@ // Use the basic name (such as String or String(255)) to get the // instance of the IType object. IType returnType; - if (typeByTypeOfName.TryGetValue(name,out returnType)) + if (typeByTypeOfName.TryGetValue(name, out returnType)) { return returnType; } @@ -259,7 +259,7 @@ if (parsedName.Length < 4) { throw new ArgumentOutOfRangeException("TypeClassification.PrecisionScale", name, - "It is not a valid Precision/Scale name"); + "It is not a valid Precision/Scale name"); } typeName = parsedName[0].Trim(); @@ -372,8 +372,8 @@ { parsedTypeName = typeName.Split(lengthSplit); } - else - parsedTypeName = typeClassification == TypeClassification.PrecisionScale ? typeName.Split(precisionScaleSplit) : new string[] {typeName}; + else + parsedTypeName = typeClassification == TypeClassification.PrecisionScale ? typeName.Split(precisionScaleSplit) : new string[] { typeName }; System.Type typeClass; @@ -392,7 +392,7 @@ { try { - type = (IType) Activator.CreateInstance(typeClass); + type = (IType)Activator.CreateInstance(typeClass); } catch (Exception e) { @@ -439,11 +439,11 @@ private static Boolean IsNullableEnum(System.Type typeClass) { if (!typeClass.IsGenericType) return false; - System.Type nullable = typeof (Nullable<>); + System.Type nullable = typeof(Nullable<>); if (!nullable.Equals(typeClass.GetGenericTypeDefinition())) return false; System.Type genericClass = typeClass.GetGenericArguments()[0]; - return genericClass.IsSubclassOf(typeof (Enum)); + return genericClass.IsSubclassOf(typeof(Enum)); } @@ -604,12 +604,12 @@ /// <summary> /// A one-to-one association type for the given class and cascade style. /// </summary> - public static EntityType OneToOne(string persistentClass, ForeignKeyDirection foreignKeyType, string uniqueKeyPropertyName, + public static EntityType OneToOne(string persistentClass, ForeignKeyDirection foreignKeyType, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool isEmbeddedInXML, string entityName, string propertyName) { return new OneToOneType(persistentClass, foreignKeyType, uniqueKeyPropertyName, lazy, unwrapProxy, isEmbeddedInXML, - entityName, propertyName); + entityName, propertyName); } /// <summary> @@ -633,7 +633,7 @@ /// <summary> /// A many-to-one association type for the given class and cascade style. /// </summary> - public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, + public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool isEmbeddedInXML, bool ignoreNotFound) { return new ManyToOneType(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, isEmbeddedInXML, ignoreNotFound); @@ -796,15 +796,17 @@ return new OrderedSetType(role, propertyRef, embedded); } + + private static CollectionType CreateCollectionType( System.Type genericCollectionType, string role, string propertyRef, params System.Type[] typeArguments) { - return (CollectionType) Activator.CreateInstance( - genericCollectionType.MakeGenericType(typeArguments), - role, propertyRef); + return (CollectionType)Activator.CreateInstance( + genericCollectionType.MakeGenericType(typeArguments), + role, propertyRef); } private static CollectionType CreateSortedCollectionType( @@ -814,11 +816,20 @@ object comparer, params System.Type[] typeArguments) { - return (CollectionType) Activator.CreateInstance( - genericCollectionType.MakeGenericType(typeArguments), - role, propertyRef, comparer); + return (CollectionType)Activator.CreateInstance( + genericCollectionType.MakeGenericType(typeArguments), + role, propertyRef, comparer); } + private static CollectionType CreateOrderedCollectionType(System.Type genericCollectionType, + string role, + string propertyRef, + params System.Type[] typeArguments) + { + return + (CollectionType)Activator.CreateInstance(genericCollectionType.MakeGenericType(typeArguments), role, propertyRef); + } + /// <summary> /// Creates a new <see cref="CollectionType"/> for an /// <see cref="System.Collections.Generic.IList{T}"/> with bag semantics. @@ -901,24 +912,24 @@ /// A <see cref="MapType"/> for the specified role. /// </returns> public static CollectionType GenericMap(string role, string propertyRef, System.Type indexClass, - System.Type elementClass) + System.Type elementClass) { return CreateCollectionType(typeof(GenericMapType<,>), role, propertyRef, indexClass, elementClass); } public static CollectionType GenericSortedList(string role, string propertyRef, object comparer, - System.Type indexClass, System.Type elementClass) + System.Type indexClass, System.Type elementClass) { return CreateSortedCollectionType(typeof(GenericSortedListType<,>), role, propertyRef, comparer, indexClass, elementClass); } public static CollectionType GenericSortedDictionary(string role, string propertyRef, object comparer, - System.Type indexClass, System.Type elementClass) + System.Type indexClass, System.Type elementClass) { return CreateSortedCollectionType(typeof(GenericSortedDictionaryType<,>), role, propertyRef, comparer, indexClass, - elementClass); + elementClass); } /// <summary> @@ -946,11 +957,26 @@ /// <param name="elementType">The type of the elements in the set.</param> /// <returns>A <see cref="GenericSetType{T}" /> for the specified role.</returns> public static CollectionType GenericSortedSet(string role, string propertyRef, object comparer, - System.Type elementType) + System.Type elementType) { return CreateSortedCollectionType(typeof(GenericSortedSetType<>), role, propertyRef, comparer, elementType); } + /// <summary> + /// Creates a new <see cref="CollectionType"/> for an ordered <see cref="Iesi.Collections.Generic.ISet{T}" />. + /// </summary> + /// <param name="role">The role the collection is in.</param> + /// <param name="propertyRef">The name of the property in the + /// owner object containing the collection ID, or <see langword="null" /> if it is + /// the primary key.</param> + /// <param name="elementType">The type of the elements in the set.</param> + /// <returns>A <see cref="GenericSetType{T}" /> for the specified role.</returns> + public static CollectionType GenericOrderedSet(string role, string propertyRef, + System.Type elementType) + { + return CreateOrderedCollectionType(typeof(GenericOrderedSetType<>), role, propertyRef, elementType); + } + /// <summary> Deep copy a series of values from one array to another... </summary> /// <param name="values">The values to copy (the source) </param> /// <param name="types">The value types </param> @@ -1137,7 +1163,7 @@ /// <param name="copiedAlready">Represent a cache of already replaced state </param> /// <returns> The replaced state </returns> public static object[] Replace(object[] original, object[] target, IType[] types, ISessionImplementor session, - object owner, IDictionary copiedAlready) + object owner, IDictionary copiedAlready) { object[] copied = new object[original.Length]; for (int i = 0; i < original.Length; i++) @@ -1159,7 +1185,7 @@ /// <param name="copyCache">A map representing a cache of already replaced state </param> /// <param name="foreignKeyDirection">FK directionality to be applied to the replacement </param> /// <returns> The replaced state </returns> - public static object[] Replace(object[] original, object[] target, IType[] types, + public static object[] Replace(object[] original, object[] target, IType[] types, ISessionImplementor session, object owner, IDictionary copyCache, ForeignKeyDirection foreignKeyDirection) { object[] copied = new object[original.Length]; @@ -1192,7 +1218,7 @@ /// If the corresponding type is a component type, then apply <see cref="ReplaceAssociations"/> /// across the component subtypes but do not replace the component value itself. /// </remarks> - public static object[] ReplaceAssociations(object[] original, object[] target, IType[] types, + public static object[] ReplaceAssociations(object[] original, object[] target, IType[] types, ISessionImplementor session, object owner, IDictionary copyCache, ForeignKeyDirection foreignKeyDirection) { object[] copied = new object[original.Length]; @@ -1205,14 +1231,14 @@ else if (types[i].IsComponentType) { // need to extract the component values and check for subtype replacements... - IAbstractComponentType componentType = (IAbstractComponentType) types[i]; + IAbstractComponentType componentType = (IAbstractComponentType)types[i]; IType[] subtypes = componentType.Subtypes; object[] origComponentValues = original[i] == null - ? new object[subtypes.Length] - : componentType.GetPropertyValues(original[i], session); + ? new object[subtypes.Length] + : componentType.GetPropertyValues(original[i], session); object[] targetComponentValues = componentType.GetPropertyValues(target[i], session); ReplaceAssociations(origComponentValues, targetComponentValues, subtypes, session, null, copyCache, - foreignKeyDirection); + foreignKeyDirection); copied[i] = target[i]; } else if (!types[i].IsAssociationType) @@ -1242,7 +1268,7 @@ CustomCollectionType result = new CustomCollectionType(typeClass, role, propertyRef, embedded); if (typeParameters != null) { - InjectParameters(result.UserType, (IDictionary) typeParameters); + InjectParameters(result.UserType, (IDictionary)typeParameters); } return result; } @@ -1251,7 +1277,7 @@ { if (type is IParameterizedType) { - ((IParameterizedType) type).SetParameterValues(parameters); + ((IParameterizedType)type).SetParameterValues(parameters); } else if (parameters != null && !(parameters.Count == 0)) { Added: trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/A.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/A.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/A.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -0,0 +1,19 @@ +using Iesi.Collections.Generic; + +namespace NHibernate.Test.GenericTest.OrderedSetGeneric +{ + public class A + { + private ISet<B> _items = new OrderedSet<B>(); + + public int Id { get; set; } + + public string Name { get; set; } + + public virtual ISet<B> Items + { + get { return _items; } + set { _items = value; } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/B.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/B.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/B.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -0,0 +1,13 @@ +namespace NHibernate.Test.GenericTest.OrderedSetGeneric +{ + public class B + { + public virtual int Id { get; set; } + + public virtual int OrderBy { get; set; } + + public virtual string Name { get; set; } + + public virtual int AId { get; set; } + } +} Property changes on: trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/B.cs ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.cs 2008-09-29 22:46:17 UTC (rev 3807) @@ -0,0 +1,64 @@ +using System.Collections; +using NUnit.Framework; + +namespace NHibernate.Test.GenericTest.OrderedSetGeneric +{ + [TestFixture] + public class OrderedSetFixture : TestCase + { + protected override IList Mappings + { + get { return new[] {"GenericTest.OrderedSetGeneric.OrderedSetFixture.hbm.xml"}; } + } + + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override void OnTearDown() + { + using (ISession s = OpenSession()) + { + using (ITransaction tx = s.BeginTransaction()) + { + s.Delete("from B"); + s.Delete("from A"); + tx.Commit(); + } + } + } + + [Test] + public void OrderedSetIsInOrder() + { + var names = new[] {"First B", "Second B"}; + const int TheId = 100; + + var a = new A {Name = "First", Id = TheId}; + + var b = new B {Name = names[1], OrderBy = 3, AId = TheId}; + a.Items.Add(b); + + var b2 = new B {Name = names[0], OrderBy = 1, AId = TheId}; + a.Items.Add(b2); + + ISession s = OpenSession(); + s.Save(a); + s.Flush(); + s.Close(); + + s = OpenSession(); + var newA = s.Get<A>(a.Id); + + Assert.AreEqual(2, newA.Items.Count); + int counter = 0; + foreach (B item in newA.Items) + { + Assert.AreEqual(names[counter], item.Name); + counter++; + } + s.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GenericTest/OrderedSetGeneric/OrderedSetFixture.hbm.xml 2008-09-29 22:46:17 UTC (rev 3807) @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.GenericTest.OrderedSetGeneric"> + + <class name="A" table="a" lazy="false"> + <id name="Id" column="id"> + <generator class="assigned" /> + </id> + <property name="Name" column="aname" /> + <set name="Items" cascade="save-update" order-by="OrderBy ASC"> + <key column="aid"/> + <one-to-many class="B"/> + </set> + </class> + + <class name="B" table="b"> + <id name="Id" column="id"> + <generator class="native" /> + </id> + <property name="AId" column="aid" /> + <property name="OrderBy" column="orderby" /> + <property name="Name" column="aname" /> + </class> +</hibernate-mapping> Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-09-29 22:14:24 UTC (rev 3806) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-09-29 22:46:17 UTC (rev 3807) @@ -257,6 +257,9 @@ <Compile Include="GenericTest\MapGeneric\B.cs" /> <Compile Include="GenericTest\MapGeneric\MapGenericFixture.cs" /> <Compile Include="GenericTest\Methods\Fixture.cs" /> + <Compile Include="GenericTest\OrderedSetGeneric\A.cs" /> + <Compile Include="GenericTest\OrderedSetGeneric\B.cs" /> + <Compile Include="GenericTest\OrderedSetGeneric\OrderedSetFixture.cs" /> <Compile Include="GenericTest\Overall\A.cs" /> <Compile Include="GenericTest\Overall\Fixture.cs" /> <Compile Include="GenericTest\SetGeneric\A.cs" /> @@ -1478,6 +1481,7 @@ <EmbeddedResource Include="Cascade\JobBatch.hbm.xml" /> <EmbeddedResource Include="Deletetransient\Person.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="GenericTest\OrderedSetGeneric\OrderedSetFixture.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1293\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1490\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1492\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |