Skip to content

Commit 70bc091

Browse files
committed
SimpleModelInspector managing polymorphic registration
SVN: trunk@5788
1 parent 82be5e5 commit 70bc091

File tree

5 files changed

+190
-19
lines changed

5 files changed

+190
-19
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Reflection;
3+
using NHibernate.Mapping.ByCode;
4+
using NUnit.Framework;
5+
using SharpTestsEx;
6+
7+
namespace NHibernate.Test.MappingByCode.MixAutomapping
8+
{
9+
public class PolymorphicPropertiesMapping
10+
{
11+
const BindingFlags RootClassPropertiesBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
12+
13+
private interface IBaseEntity
14+
{
15+
int Id { get; }
16+
}
17+
18+
private class BaseEntity : IBaseEntity
19+
{
20+
public int Id { get; protected set; }
21+
public DateTime LastChange { get { return DateTime.Now; } }
22+
}
23+
24+
private interface IProduct : IBaseEntity
25+
{
26+
string Description { get;}
27+
}
28+
29+
private abstract class BaseProduct : BaseEntity, IProduct
30+
{
31+
public abstract string Description { get; }
32+
}
33+
34+
private class Product : BaseProduct
35+
{
36+
public override string Description
37+
{
38+
get { return "blah"; }
39+
}
40+
}
41+
42+
[Test]
43+
public void WhenMapIdThroughBaseInterfaceThenFindIt()
44+
{
45+
var inspector = (IModelInspector)new SimpleModelInspector();
46+
var mapper = new ModelMapper(inspector);
47+
mapper.Class<IBaseEntity>(
48+
map =>
49+
{
50+
map.Id(x => x.Id, idmap => { });
51+
});
52+
inspector.IsPersistentId(typeof(Product).GetProperty("Id", RootClassPropertiesBindingFlags)).Should().Be.True();
53+
}
54+
55+
[Test]
56+
public void WhenMapPropertyThroughBaseConcreteClassThenFindIt()
57+
{
58+
var inspector = (IModelInspector)new SimpleModelInspector();
59+
var mapper = new ModelMapper(inspector);
60+
61+
mapper.Class<BaseEntity>(map => map.Property(x => x.LastChange));
62+
63+
inspector.IsPersistentProperty(typeof(Product).GetProperty("LastChange", RootClassPropertiesBindingFlags)).Should().Be.True();
64+
}
65+
66+
[Test]
67+
public void WhenMapPropertyThroughBaseInterfaceThenFindIt()
68+
{
69+
var inspector = (IModelInspector)new SimpleModelInspector();
70+
var mapper = new ModelMapper(inspector);
71+
72+
mapper.Class<IProduct>(map => map.Property(x => x.Description));
73+
74+
inspector.IsPersistentProperty(typeof(Product).GetProperty("Description", RootClassPropertiesBindingFlags)).Should().Be.True();
75+
}
76+
77+
[Test]
78+
public void WhenMapPropertyThroughBaseAbstractClassThenFindIt()
79+
{
80+
var inspector = (IModelInspector)new SimpleModelInspector();
81+
var mapper = new ModelMapper(inspector);
82+
83+
mapper.Class<BaseProduct>(map => map.Property(x => x.Description));
84+
85+
inspector.IsPersistentProperty(typeof(Product).GetProperty("Description", RootClassPropertiesBindingFlags)).Should().Be.True();
86+
}
87+
88+
[Test]
89+
public void WhenMapPropertyThroughClassThenFindIt()
90+
{
91+
var inspector = (IModelInspector)new SimpleModelInspector();
92+
var mapper = new ModelMapper(inspector);
93+
94+
mapper.Class<Product>(map => map.Property(x => x.Description));
95+
96+
inspector.IsPersistentProperty(typeof(Product).GetProperty("Description", RootClassPropertiesBindingFlags)).Should().Be.True();
97+
}
98+
}
99+
}

src/NHibernate.Test/MappingByCode/TypeExtensionsTests/TypeExtensionsTest.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Collections.ObjectModel;
5+
using System.Linq;
56
using System.Reflection;
67
using NHibernate.Mapping.ByCode;
78
using NUnit.Framework;
@@ -203,5 +204,41 @@ public void HasPublicPropertyOf_WhenAsDelegateThenUseDelegateToFilterProperties(
203204
typeof(MyBaseClass).HasPublicPropertyOf(typeof(string), x => false).Should().Be.False();
204205
typeof(MyBaseClass).HasPublicPropertyOf(typeof(string), x => true).Should().Be.True();
205206
}
207+
208+
private abstract class MyAbstract
209+
{
210+
protected int aField;
211+
public abstract string Description { get; }
212+
}
213+
214+
private class MyConcrete : MyAbstract
215+
{
216+
public override string Description
217+
{
218+
get { return "blah"; }
219+
}
220+
}
221+
222+
[Test]
223+
public void GetMemberFromDeclaringClasses_WhenPropertyThenFindAbstract()
224+
{
225+
var member = typeof(MyConcrete).GetProperty("Description", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
226+
var found = member.GetMemberFromDeclaringClasses().ToList();
227+
found.Count.Should().Be(2);
228+
var concreteMember = For<MyConcrete>.Property(x => x.Description).GetMemberFromReflectedType(typeof(MyConcrete));
229+
var abstractMember = For<MyAbstract>.Property(x => x.Description);
230+
found.Should().Have.SameValuesAs(concreteMember, abstractMember);
231+
}
232+
233+
[Test]
234+
public void GetMemberFromDeclaringClasses_WhenFieldThenFindAbstract()
235+
{
236+
var member = typeof(MyConcrete).GetField("aField", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
237+
var found = member.GetMemberFromDeclaringClasses().ToList();
238+
found.Count.Should().Be(1);
239+
var foundMember = found.Single();
240+
foundMember.DeclaringType.Should().Be(typeof(MyAbstract));
241+
foundMember.ReflectedType.Should().Be(typeof(MyAbstract));
242+
}
206243
}
207244
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@
592592
<Compile Include="MappingByCode\MixAutomapping\ManyToOneTest.cs" />
593593
<Compile Include="MappingByCode\MixAutomapping\OneToManyTests.cs" />
594594
<Compile Include="MappingByCode\MixAutomapping\PoidTests.cs" />
595+
<Compile Include="MappingByCode\MixAutomapping\PolymorphicPropertiesMapping.cs" />
595596
<Compile Include="MappingByCode\MixAutomapping\PropertiesExclusionTests.cs" />
596597
<Compile Include="MappingByCode\MixAutomapping\RootEntityTests.cs" />
597598
<Compile Include="MappingByCode\MixAutomapping\SetCollectionTests.cs" />

src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -530,108 +530,108 @@ bool IModelInspector.IsTablePerConcreteClass(System.Type type)
530530

531531
bool IModelInspector.IsOneToOne(MemberInfo member)
532532
{
533-
bool declaredResult = declaredModel.IsOneToOne(member);
533+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsOneToOne(m));
534534
return isOneToOne(member, declaredResult);
535535
}
536536

537537
bool IModelInspector.IsManyToOne(MemberInfo member)
538538
{
539-
bool declaredResult = declaredModel.IsManyToOne(member);
539+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsManyToOne(m));
540540
return isManyToOne(member, declaredResult);
541541
}
542542

543543
bool IModelInspector.IsManyToMany(MemberInfo member)
544544
{
545-
bool declaredResult = declaredModel.IsManyToMany(member);
545+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsManyToMany(m));
546546
return isManyToMany(member, declaredResult);
547547
}
548548

549549
bool IModelInspector.IsOneToMany(MemberInfo member)
550550
{
551-
bool declaredResult = declaredModel.IsOneToMany(member);
551+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsOneToMany(m));
552552
return isOneToMany(member, declaredResult);
553553
}
554554

555555
bool IModelInspector.IsAny(MemberInfo member)
556556
{
557-
bool declaredResult = declaredModel.IsAny(member);
557+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsAny(m));
558558
return isAny(member, declaredResult);
559559
}
560560

561561
bool IModelInspector.IsPersistentId(MemberInfo member)
562562
{
563-
bool declaredResult = declaredModel.IsPersistentId(member);
563+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsPersistentId(m));
564564
return isPersistentId(member, declaredResult);
565565
}
566566

567567
bool IModelInspector.IsMemberOfComposedId(MemberInfo member)
568568
{
569-
return declaredModel.IsPersistentId(member);
569+
return declaredModel.IsMemberOfComposedId(member);
570570
}
571571

572572
bool IModelInspector.IsVersion(MemberInfo member)
573573
{
574-
bool declaredResult = declaredModel.IsVersion(member);
574+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsVersion(m));
575575
return isVersion(member, declaredResult);
576576
}
577577

578578
bool IModelInspector.IsMemberOfNaturalId(MemberInfo member)
579579
{
580-
bool declaredResult = declaredModel.IsMemberOfNaturalId(member);
580+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsMemberOfNaturalId(m));
581581
return isMemberOfNaturalId(member, declaredResult);
582582
}
583583

584584
bool IModelInspector.IsPersistentProperty(MemberInfo member)
585585
{
586-
bool declaredResult = declaredModel.IsPersistentProperty(member);
586+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsPersistentProperty(m));
587587
return isPersistentProperty(member, declaredResult);
588588
}
589589

590590
bool IModelInspector.IsSet(MemberInfo role)
591591
{
592-
bool declaredResult = declaredModel.IsSet(role);
592+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsSet(m));
593593
return isSet(role, declaredResult);
594594
}
595595

596596
bool IModelInspector.IsBag(MemberInfo role)
597597
{
598-
bool declaredResult = declaredModel.IsBag(role);
598+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsBag(m));
599599
return isBag(role, declaredResult);
600600
}
601601

602602
bool IModelInspector.IsIdBag(MemberInfo role)
603603
{
604-
bool declaredResult = declaredModel.IsIdBag(role);
604+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsIdBag(m));
605605
return isIdBag(role, declaredResult);
606606
}
607607

608608
bool IModelInspector.IsList(MemberInfo role)
609609
{
610-
bool declaredResult = declaredModel.IsList(role);
610+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsList(m));
611611
return isList(role, declaredResult);
612612
}
613613

614614
bool IModelInspector.IsArray(MemberInfo role)
615615
{
616-
bool declaredResult = declaredModel.IsArray(role);
616+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsArray(m));
617617
return isArray(role, declaredResult);
618618
}
619619

620620
bool IModelInspector.IsDictionary(MemberInfo role)
621621
{
622-
bool declaredResult = declaredModel.IsDictionary(role);
622+
bool declaredResult = DeclaredPolymorphicMatch(role, m => declaredModel.IsDictionary(m));
623623
return isDictionary(role, declaredResult);
624624
}
625625

626626
bool IModelInspector.IsProperty(MemberInfo member)
627627
{
628-
bool declaredResult = declaredModel.IsProperty(member);
628+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsProperty(m));
629629
return isProperty(member, declaredResult);
630630
}
631631

632632
bool IModelInspector.IsDynamicComponent(MemberInfo member)
633633
{
634-
bool declaredResult = declaredModel.IsDynamicComponent(member);
634+
bool declaredResult = DeclaredPolymorphicMatch(member, m => declaredModel.IsDynamicComponent(m));
635635
return isDynamicComponent(member, declaredResult);
636636
}
637637

@@ -652,6 +652,13 @@ IEnumerable<string> IModelInspector.GetPropertiesSplits(System.Type type)
652652

653653
#endregion
654654

655+
protected virtual bool DeclaredPolymorphicMatch(MemberInfo member, Func<MemberInfo, bool> declaredMatch)
656+
{
657+
return declaredMatch(member)
658+
|| member.GetMemberFromDeclaringClasses().Any(declaredMatch)
659+
|| member.GetPropertyFromInterfaces().Any(declaredMatch);
660+
}
661+
655662
public void IsRootEntity(Func<System.Type, bool, bool> match)
656663
{
657664
if (match == null)

src/NHibernate/Mapping/ByCode/TypeExtensions.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,34 @@ public static MemberInfo GetMemberFromDeclaringType(this MemberInfo source)
170170
{
171171
return source;
172172
}
173-
return source.DeclaringType.GetProperty(source.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
173+
if (source is PropertyInfo)
174+
{
175+
return source.DeclaringType.GetProperty(source.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
176+
}
177+
if (source is FieldInfo)
178+
{
179+
return source.DeclaringType.GetField(source.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
180+
}
181+
return null;
182+
}
183+
184+
public static IEnumerable<MemberInfo> GetMemberFromDeclaringClasses(this MemberInfo source)
185+
{
186+
if (source == null)
187+
{
188+
throw new ArgumentNullException("source");
189+
}
190+
if (source is PropertyInfo)
191+
{
192+
var reflectedType = source.ReflectedType;
193+
var memberType = source.GetPropertyOrFieldType();
194+
return reflectedType.GetPropertiesOfHierarchy().Cast<PropertyInfo>().Where(x => source.Name.Equals(x.Name) && memberType.Equals(x.PropertyType)).Cast<MemberInfo>();
195+
}
196+
if (source is FieldInfo)
197+
{
198+
return new[] { source.GetMemberFromDeclaringType() };
199+
}
200+
return Enumerable.Empty<MemberInfo>();
174201
}
175202

176203
public static IEnumerable<MemberInfo> GetPropertyFromInterfaces(this MemberInfo source)

0 commit comments

Comments
 (0)