Skip to content

Commit e86544e

Browse files
committed
NH-3269 - Do not map base class properties by inherited class mapping
1 parent 4bb74a8 commit e86544e

File tree

6 files changed

+193
-75
lines changed

6 files changed

+193
-75
lines changed

src/NHibernate.Test/MappingByCode/ExplicitMappingTests/AllPropertiesRegistrationTests.cs

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -113,41 +113,6 @@ private class Inherited:MyClass
113113

114114
}
115115

116-
[Test]
117-
public void WhenMapPropertiesInTheInheritedThenMapInBase()
118-
{
119-
// without ignoring MyClass as root-class I will try to map all properties using the inherited class.
120-
// NH have to recognize the case and, following Object-Relational-Mapping rules, map those properties in the base class.
121-
// Where needed, using the SimpleModelInspector, the user can revert this behavior checking the DeclaringType and ReflectedType of the persistent member.
122-
var mapper = new ModelMapper();
123-
mapper.Class<MyClass>(mc => mc.Id(x => x.Id));
124-
mapper.JoinedSubclass<Inherited>(mc =>
125-
{
126-
mc.Property(x => x.Simple, map => map.Access(Accessor.Field));
127-
mc.Property(x => x.ComplexType, map => map.Access(Accessor.Field));
128-
mc.Bag(x => x.Bag, y => y.Access(Accessor.Field));
129-
mc.IdBag(x => x.IdBag, y => y.Access(Accessor.Field));
130-
mc.List(x => x.List, y => y.Access(Accessor.Field));
131-
mc.Set(x => x.Set, y => y.Access(Accessor.Field));
132-
mc.Map(x => x.Map, y => y.Access(Accessor.Field));
133-
mc.OneToOne(x => x.OneToOne, y => y.Access(Accessor.Field));
134-
mc.ManyToOne(x => x.ManyToOne, y => y.Access(Accessor.Field));
135-
mc.Any(x => x.Any, typeof(int), y => y.Access(Accessor.Field));
136-
mc.Component(x => x.DynamicCompo, new { A=2 }, y => y.Access(Accessor.Field));
137-
mc.Component(x => x.Compo, y =>
138-
{
139-
y.Access(Accessor.Field);
140-
y.Property(c => c.Something);
141-
});
142-
});
143-
var mappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
144-
var hbmClass = mappings.RootClasses[0];
145-
var hbmJoinedSubclass = mappings.JoinedSubclasses[0];
146-
hbmClass.Properties.Select(p => p.Name).Should().Have.SameValuesAs("Simple", "ComplexType", "Bag", "IdBag", "List", "Set", "Map", "Compo", "OneToOne", "ManyToOne", "Any", "DynamicCompo");
147-
hbmClass.Properties.Select(p => p.Access).All(x=> x.Satisfy(access=> access.Contains("field.")));
148-
hbmJoinedSubclass.Properties.Should().Be.Empty();
149-
}
150-
151116
[Test]
152117
public void WhenMapPropertiesInTheBaseJumpedClassThenMapInInherited()
153118
{
@@ -186,41 +151,7 @@ public void WhenMapPropertiesInTheBaseJumpedClassThenMapInInherited()
186151
hbmClass.Properties.Select(p => p.Access).All(x => x.Satisfy(access => access.Contains("field.")));
187152
}
188153

189-
[Test]
190-
public void WhenMapPropertiesInTheInheritedUsingMemberNameThenMapInBase()
191-
{
192-
// without ignoring MyClass as root-class I will try to map all properties using the inherited class.
193-
// NH have to recognize the case and, following Object-Relational-Mapping rules, map those properties in the base class.
194-
var mapper = new ModelMapper();
195-
mapper.Class<MyClass>(mc => mc.Id(x => x.Id));
196-
mapper.JoinedSubclass<Inherited>(mc =>
197-
{
198-
mc.Property("Simple", map => map.Access(Accessor.Field));
199-
mc.Property("ComplexType", map => map.Access(Accessor.Field));
200-
mc.Bag<string>("Bag", y => y.Access(Accessor.Field));
201-
mc.IdBag<MyCompo>("IdBag", y => y.Access(Accessor.Field));
202-
mc.List<string>("List", y => y.Access(Accessor.Field));
203-
mc.Set<string>("Set", y => y.Access(Accessor.Field));
204-
mc.Map<int, string>("Map", y => y.Access(Accessor.Field));
205-
mc.OneToOne<Related>("OneToOne", y => y.Access(Accessor.Field));
206-
mc.ManyToOne<Related>("ManyToOne", y => y.Access(Accessor.Field));
207-
mc.Any<object>("Any", typeof(int), y => y.Access(Accessor.Field));
208-
mc.Component("DynamicCompo", new { A = 2 }, y => y.Access(Accessor.Field));
209-
mc.Component<MyCompo>("Compo", y =>
210-
{
211-
y.Access(Accessor.Field);
212-
y.Property(c => c.Something);
213-
});
214-
});
215-
var mappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
216-
var hbmClass = mappings.RootClasses[0];
217-
var hbmJoinedSubclass = mappings.JoinedSubclasses[0];
218-
hbmClass.Properties.Select(p => p.Name).Should().Have.SameValuesAs("Simple", "ComplexType", "Bag", "IdBag", "List", "Set", "Map", "Compo", "OneToOne", "ManyToOne", "Any", "DynamicCompo");
219-
hbmClass.Properties.Select(p => p.Access).All(x => x.Satisfy(access => access.Contains("field.")));
220-
hbmJoinedSubclass.Properties.Should().Be.Empty();
221-
}
222-
223-
[Test]
154+
[Test]
224155
public void WhenMapPropertiesInTheBaseJumpedClassUsingMemberNameThenMapInInherited()
225156
{
226157
// ignoring MyClass and using Inherited, as root-class, I will try to map all properties using the base class.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Mapping.ByCode;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3269
6+
{
7+
public class FixtureNonPublicProperty : TestCaseMappingByCode
8+
{
9+
[Test]
10+
public void ShouldThrowExceptionWhenTryingToSaveInherited1WithDuplicateName()
11+
{
12+
using (var session = OpenSession())
13+
using (var transaction = session.BeginTransaction())
14+
{
15+
var e1 = new Inherited1 { Name = "Bob" };
16+
session.Save(e1);
17+
18+
Assert.That(() => { transaction.Commit(); }, Throws.Exception);
19+
}
20+
}
21+
22+
[Test]
23+
public void ShouldNotThrowExceptionWhenTryingToSaveInherited2WithDuplicateName()
24+
{
25+
using (var session = OpenSession())
26+
using (var transaction = session.BeginTransaction())
27+
{
28+
var e2 = new Inherited2 { Name = "Sally" };
29+
session.Save(e2);
30+
31+
transaction.Commit();
32+
}
33+
}
34+
35+
protected override HbmMapping GetMappings()
36+
{
37+
var mapper = new ModelMapper();
38+
39+
mapper.Class<Inherited1>(rc =>
40+
{
41+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
42+
rc.Property("Name", m => m.UniqueKey("Inherited1_UX_Name"));
43+
});
44+
45+
mapper.Class<Inherited2>(rc =>
46+
{
47+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
48+
rc.Property("Name", m => m.Length(200));
49+
});
50+
51+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
52+
}
53+
54+
protected override void OnSetUp()
55+
{
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
var e1 = new Inherited1 { Name = "Bob" };
60+
session.Save(e1);
61+
62+
var e2 = new Inherited2 { Name = "Sally" };
63+
session.Save(e2);
64+
65+
session.Flush();
66+
transaction.Commit();
67+
}
68+
}
69+
70+
protected override void OnTearDown()
71+
{
72+
using (var session = OpenSession())
73+
using (var transaction = session.BeginTransaction())
74+
{
75+
session.Delete("from System.Object");
76+
77+
session.Flush();
78+
transaction.Commit();
79+
}
80+
}
81+
}
82+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Mapping.ByCode;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3269
6+
{
7+
public class FixturePublicProperty : TestCaseMappingByCode
8+
{
9+
[Test]
10+
public void ShouldThrowExceptionWhenTryingToSaveInherited1WithDuplicateName()
11+
{
12+
using (var session = OpenSession())
13+
using (var transaction = session.BeginTransaction())
14+
{
15+
var e1 = new Inherited1 { Name = "Bob" };
16+
session.Save(e1);
17+
18+
Assert.That(() => { transaction.Commit(); }, Throws.Exception);
19+
}
20+
}
21+
22+
[Test]
23+
public void ShouldNotThrowExceptionWhenTryingToSaveInherited2WithDuplicateName()
24+
{
25+
using (var session = OpenSession())
26+
using (var transaction = session.BeginTransaction())
27+
{
28+
var e2 = new Inherited2 { Name = "Sally" };
29+
session.Save(e2);
30+
31+
transaction.Commit();
32+
}
33+
}
34+
35+
protected override HbmMapping GetMappings()
36+
{
37+
var mapper = new ModelMapper();
38+
39+
mapper.Class<Inherited1>(rc =>
40+
{
41+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
42+
rc.Property(x => x.Name, m => m.UniqueKey("Inherited1_UX_Name"));
43+
});
44+
45+
mapper.Class<Inherited2>(rc =>
46+
{
47+
rc.Id(x => x.Id, m => m.Generator(Generators.Guid));
48+
rc.Property(x => x.Name, m => m.Length(200));
49+
});
50+
51+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
52+
}
53+
54+
protected override void OnSetUp()
55+
{
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
var e1 = new Inherited1 { Name = "Bob" };
60+
session.Save(e1);
61+
62+
var e2 = new Inherited2 { Name = "Sally" };
63+
session.Save(e2);
64+
65+
session.Flush();
66+
transaction.Commit();
67+
}
68+
}
69+
70+
protected override void OnTearDown()
71+
{
72+
using (var session = OpenSession())
73+
using (var transaction = session.BeginTransaction())
74+
{
75+
session.Delete("from System.Object");
76+
77+
session.Flush();
78+
transaction.Commit();
79+
}
80+
}
81+
}
82+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
3+
namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3269
4+
{
5+
public abstract class Base
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
11+
public class Inherited1 : Base
12+
{
13+
public virtual string F1 { get; set; }
14+
}
15+
16+
public class Inherited2 : Base
17+
{
18+
public virtual string F2 { get; set; }
19+
}
20+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@
714714
<Compile Include="NHSpecificTest\NH3324\ChildEntity.cs" />
715715
<Compile Include="NHSpecificTest\NH3324\Entity.cs" />
716716
<Compile Include="NHSpecificTest\NH3324\FixtureByCode.cs" />
717+
<Compile Include="MappingByCode\IntegrationTests\NH3269\FixtureNonPublicProperty.cs" />
718+
<Compile Include="MappingByCode\IntegrationTests\NH3269\Model.cs" />
719+
<Compile Include="MappingByCode\IntegrationTests\NH3269\FixturePublicProperty.cs" />
717720
<Compile Include="NHSpecificTest\NH3374\Document.cs" />
718721
<Compile Include="NHSpecificTest\NH3374\FixtureByCode.cs" />
719722
<Compile Include="NHSpecificTest\NH2042\Model.cs" />

src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ public void Property<TProperty>(Expression<Func<TEntity, TProperty>> property, A
4141

4242
protected virtual void RegisterPropertyMapping<TProperty>(Expression<Func<TEntity, TProperty>> property, Action<IPropertyMapper> mapping)
4343
{
44-
MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property);
4544
MemberInfo memberOf = TypeExtensions.DecodeMemberAccessExpressionOf(property);
46-
RegistePropertyMapping(mapping, member, memberOf);
45+
RegistePropertyMapping(mapping, memberOf);
4746
}
4847

4948
public void Property(string notVisiblePropertyOrFieldName, Action<IPropertyMapper> mapping)
@@ -57,7 +56,7 @@ protected virtual void RegisterNoVisiblePropertyMapping(string notVisiblePropert
5756
// done unsing expressions are faster than those done with pure reflection.
5857
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
5958
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TEntity));
60-
RegistePropertyMapping(mapping, member, memberOf);
59+
RegistePropertyMapping(mapping, memberOf);
6160
}
6261

6362
protected void RegistePropertyMapping(Action<IPropertyMapper> mapping, params MemberInfo[] members)
@@ -69,11 +68,12 @@ protected void RegistePropertyMapping(Action<IPropertyMapper> mapping, params Me
6968
}
7069
}
7170

72-
public void Component<TComponent>(Expression<Func<TEntity, TComponent>> property,
73-
Action<IComponentMapper<TComponent>> mapping) where TComponent : class
71+
public void Component<TComponent>(Expression<Func<TEntity, TComponent>> property, Action<IComponentMapper<TComponent>> mapping)
72+
where TComponent : class
7473
{
7574
RegisterComponentMapping(property, mapping);
7675
}
76+
7777
public void Component<TComponent>(Expression<Func<TEntity, TComponent>> property) where TComponent : class
7878
{
7979
RegisterComponentMapping(property, x => { });

0 commit comments

Comments
 (0)