Skip to content

Commit f096548

Browse files
committed
Process classes accordingly to inheritance path in mapping by code
In some rare cases the old code did not work as it was intended because comparison algorithm doesn't always compare the types directly, but instead the comparison can be made through a 3rd type. Adapt the sample provided by @rrutkows to demonstrate the issue.
1 parent 5c18452 commit f096548

File tree

4 files changed

+53
-69
lines changed

4 files changed

+53
-69
lines changed

src/NHibernate.Test/NHSpecificTest/NH2931/Fixture.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using NHibernate.Mapping.ByCode;
1+
using NHibernate.Mapping.ByCode;
32
using NUnit.Framework;
43
using System.Linq;
54

@@ -12,21 +11,28 @@ public class MappingByCodeTest
1211
public void CompiledMappings_ShouldNotDependOnAddedOrdering_AddedBy_AddMapping()
1312
{
1413
var mapper = new ModelMapper();
15-
mapper.AddMapping<EntityMapping>();
16-
mapper.AddMapping<DerivedClassMapping>();
17-
mapper.AddMapping<BaseClassMapping>();
14+
mapper.AddMapping<AMapping>();
15+
mapper.AddMapping<BMapping>();
16+
mapper.AddMapping<CMapping>();
17+
mapper.AddMapping<DMapping>();
18+
mapper.AddMapping<EMapping>();
19+
mapper.AddMapping<FMapping>();
20+
mapper.AddMapping<GMapping>();
1821
var config = TestConfigurationHelper.GetDefaultConfiguration();
1922
Assert.DoesNotThrow(() => config.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities()));
2023
}
2124

2225
[Test]
2326
public void CompiledMappings_ShouldNotDependOnAddedOrdering_AddedBy_AddMappings()
2427
{
28+
var mappings =
29+
typeof(MappingByCodeTest)
30+
.Assembly
31+
.GetExportedTypes()
32+
//only add our test entities/mappings
33+
.Where(t => t.Namespace == typeof(MappingByCodeTest).Namespace && t.Name.EndsWith("Mapping"));
2534
var mapper = new ModelMapper();
26-
mapper.AddMappings(typeof(EntityMapping).Assembly
27-
.GetExportedTypes()
28-
//only add our test entities/mappings
29-
.Where(t => t.Namespace == typeof(MappingByCodeTest).Namespace));
35+
mapper.AddMappings(mappings);
3036
var config = TestConfigurationHelper.GetDefaultConfiguration();
3137
Assert.DoesNotThrow(() => config.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities()));
3238
}
Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,18 @@
1-
using NHibernate.Mapping.ByCode;
2-
using NHibernate.Mapping.ByCode.Conformist;
1+
using NHibernate.Mapping.ByCode.Conformist;
32

43
namespace NHibernate.Test.NHSpecificTest.NH2931
54
{
6-
public class EntityMapping : ClassMapping<Entity>
7-
{
8-
public EntityMapping()
9-
{
10-
Id(i => i.Id, m => m.Generator(Generators.GuidComb));
11-
}
12-
}
13-
//NOTE: tests may work if the order of mappings is
14-
// 1) BaseClassMapping
15-
// 2) DerivedClassMapping
16-
//but they always fail when
17-
// 1) DerivedClassMapping
18-
// 2) BaseClassMapping
19-
//MappingByCodeTest.CompiledMappings_ShouldNotDependOnAddedOrdering_AddedBy_AddMapping
20-
// explicitly forces the first ordering to occur, but the most common use is simply
21-
// typeof(SomeEntity).Assembly.GetTypes() to register everything; as shown in
22-
//MappingByCodeTest.CompiledMappings_ShouldNotDependOnAddedOrdering_AddedBy_AddMappings
23-
public class DerivedClassMapping : JoinedSubclassMapping<DerivedClass>
24-
{
25-
public DerivedClassMapping()
26-
{
27-
Property(p => p.DerivedProperty);
28-
}
29-
}
30-
public class BaseClassMapping : JoinedSubclassMapping<BaseClass>
31-
{
32-
public BaseClassMapping()
33-
{
34-
Property(p => p.BaseProperty);
35-
}
36-
}
5+
public class AMapping : JoinedSubclassMapping<A> {}
6+
7+
public class BMapping : ClassMapping<B> {}
8+
9+
public class CMapping : JoinedSubclassMapping<C> {}
10+
11+
public class DMapping : JoinedSubclassMapping<D> {}
12+
13+
public class EMapping : JoinedSubclassMapping<E> {}
14+
15+
public class FMapping : JoinedSubclassMapping<F> {}
16+
17+
public class GMapping : ClassMapping<G> {}
3718
}
Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
using System;
2-
3-
namespace NHibernate.Test.NHSpecificTest.NH2931
1+
namespace NHibernate.Test.NHSpecificTest.NH2931
42
{
5-
public abstract class Entity
6-
{
7-
public Guid Id { get; private set; }
8-
}
9-
public class BaseClass : Entity
10-
{
11-
public string BaseProperty { get; set; }
12-
}
13-
public class DerivedClass : BaseClass
14-
{
15-
public string DerivedProperty { get; set; }
16-
}
3+
public class A : F{ }
4+
5+
public class B { }
6+
7+
public class C : B { }
8+
9+
public class D : B { }
10+
11+
public class E : F { }
12+
13+
public class F : G { }
14+
15+
public class G { }
1716
}

src/NHibernate/Mapping/ByCode/ModelMapper.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,7 @@ public HbmMapping CompileMappingFor(IEnumerable<System.Type> types)
549549
throw new ArgumentNullException("types");
550550
}
551551

552-
var typeToMap = types.Distinct()
553-
.OrderBy(x => x, new TypeHierarchyComparer())
554-
.ToList();
552+
var typeToMap = OrderTypesByHierarchy(types);
555553

556554
string defaultAssemblyName = null;
557555
string defaultNamespace = null;
@@ -583,9 +581,7 @@ public IEnumerable<HbmMapping> CompileMappingForEach(IEnumerable<System.Type> ty
583581
{
584582
throw new ArgumentNullException("types");
585583
}
586-
var typeToMap = types.Distinct()
587-
.OrderBy(x => x, new TypeHierarchyComparer())
588-
.ToList();
584+
var typeToMap = OrderTypesByHierarchy(types);
589585

590586
//NH-2831: always use the full name of the assembly because it may come from GAC
591587
foreach (var type in RootClasses(typeToMap))
@@ -1809,15 +1805,17 @@ public IEnumerable<HbmMapping> CompileMappingForEachExplicitlyAddedEntity()
18091805
return CompileMappingForEach(customizerHolder.GetAllCustomizedEntities());
18101806
}
18111807

1812-
private class TypeHierarchyComparer : IComparer<System.Type>
1808+
private static List<System.Type> OrderTypesByHierarchy(IEnumerable<System.Type> types)
18131809
{
1814-
public int Compare(System.Type x, System.Type y)
1810+
var typesCache = new HashSet<System.Type>(types);
1811+
1812+
var result = new List<System.Type>(typesCache.Count);
1813+
while (typesCache.Count > 0)
18151814
{
1816-
if (x == y) return 0;
1817-
if (x.IsAssignableFrom(y)) return -1;
1818-
if (y.IsAssignableFrom(x)) return 1;
1819-
return 0;
1815+
var type = typesCache.First();
1816+
result.AddRange(type.GetHierarchyFromBase().Where(baseType => typesCache.Remove(baseType)));
18201817
}
1818+
return result;
18211819
}
18221820
}
18231821
}

0 commit comments

Comments
 (0)