Skip to content

Commit 4bb74a8

Browse files
committed
Merge pull request #150 from hazzik/NH-3041
Fix for NH-3041
2 parents 30b786d + ac488a4 commit 4bb74a8

File tree

9 files changed

+185
-40
lines changed

9 files changed

+185
-40
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3041
2+
{
3+
public class PersonDetail
4+
{
5+
public virtual string LastName { get; set; }
6+
public virtual Person Person { get; set; }
7+
public virtual int? PersonDetailId { get; set; }
8+
}
9+
10+
public class Person
11+
{
12+
public virtual string FirstName { get; set; }
13+
public virtual PersonDetail PersonDetail { get; set; }
14+
public virtual int? PersonId { get; set; }
15+
}
16+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Mapping.ByCode;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3041
6+
{
7+
[TestFixture]
8+
public class OneToOneToPropertyReference : TestCaseMappingByCode
9+
{
10+
protected override void OnSetUp()
11+
{
12+
using (var session = OpenSession())
13+
using (var tx = session.BeginTransaction())
14+
{
15+
var person1 = new Person { FirstName = "Jack" };
16+
session.Save(person1);
17+
18+
var person2 = new Person { FirstName = "Robert" };
19+
session.Save(person2);
20+
21+
var personDetail = new PersonDetail { LastName = "Smith", Person = person1 };
22+
session.Save(personDetail);
23+
24+
tx.Commit();
25+
}
26+
}
27+
28+
protected override void OnTearDown()
29+
{
30+
using (var session = OpenSession())
31+
using (var tx = session.BeginTransaction())
32+
{
33+
session.Delete("from System.Object");
34+
tx.Commit();
35+
}
36+
}
37+
38+
protected override HbmMapping GetMappings()
39+
{
40+
var mapper = new ModelMapper();
41+
mapper.Class<PersonDetail>(m =>
42+
{
43+
m.Id(t => t.PersonDetailId, a => a.Generator(Generators.Identity));
44+
m.Property(t => t.LastName,
45+
c =>
46+
{
47+
c.NotNullable(true);
48+
c.Length(32);
49+
});
50+
m.ManyToOne(t => t.Person,
51+
c =>
52+
{
53+
c.Column("PersonId");
54+
c.Unique(true);
55+
c.NotNullable(false);
56+
c.NotFound(NotFoundMode.Ignore);
57+
});
58+
});
59+
60+
mapper.Class<Person>(m =>
61+
{
62+
m.Id(t => t.PersonId, a => a.Generator(Generators.Identity));
63+
m.Property(t => t.FirstName,
64+
c =>
65+
{
66+
c.NotNullable(true);
67+
c.Length(32);
68+
});
69+
m.OneToOne(t => t.PersonDetail,
70+
oo =>
71+
{
72+
oo.PropertyReference(x => x.Person);
73+
oo.Cascade(Mapping.ByCode.Cascade.All);
74+
});
75+
});
76+
77+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
78+
}
79+
80+
[Test]
81+
public void ShouldConfigureSessionCorrectly()
82+
{
83+
using (var session = OpenSession())
84+
{
85+
var person1 = session.Get<Person>(1);
86+
var person2 = session.Get<Person>(2);
87+
var personDetail = session.Get<PersonDetail>(1);
88+
89+
Assert.IsNull(person2.PersonDetail);
90+
Assert.IsNotNull(person1.PersonDetail);
91+
Assert.AreEqual(person1.PersonDetail.LastName, personDetail.LastName);
92+
Assert.AreEqual(person1.FirstName, personDetail.Person.FirstName);
93+
}
94+
}
95+
}
96+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,8 @@
586586
<Compile Include="MappingByCode\ExplicitMappingTests\VersionTests.cs" />
587587
<Compile Include="MappingByCode\For.cs" />
588588
<Compile Include="MappingByCode\ImportTests.cs" />
589+
<Compile Include="MappingByCode\IntegrationTests\NH3041\Domain.cs" />
590+
<Compile Include="MappingByCode\IntegrationTests\NH3041\OneToOneToPropertyReference.cs" />
589591
<Compile Include="MappingByCode\IntegrationTests\NH2728\Cat.cs" />
590592
<Compile Include="MappingByCode\IntegrationTests\NH2728\Dog.cs" />
591593
<Compile Include="MappingByCode\IntegrationTests\NH2728\IAnimal.cs" />

src/NHibernate/Mapping/ByCode/IOneToOneMapper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Linq.Expressions;
13
using System.Reflection;
24

35
namespace NHibernate.Mapping.ByCode
@@ -11,4 +13,9 @@ public interface IOneToOneMapper : IEntityPropertyMapper
1113
void Formula(string formula);
1214
void ForeignKey(string foreignKeyName);
1315
}
16+
17+
public interface IOneToOneMapper<T> : IOneToOneMapper
18+
{
19+
void PropertyReference<TProperty>(Expression<Func<T, TProperty>> reference);
20+
}
1421
}

src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ void Component<TComponent>(Expression<Func<TContainer, TComponent>> property,
4141
Action<IComponentMapper<TComponent>> mapping) where TComponent : class;
4242
void Component<TComponent>(Expression<Func<TContainer, TComponent>> property) where TComponent : class;
4343
void Component<TComponent>(Expression<Func<TContainer, IDictionary>> property,
44-
TComponent dynamicComponentTemplate,
45-
Action<IDynamicComponentMapper<TComponent>> mapping) where TComponent : class;
44+
TComponent dynamicComponentTemplate,
45+
Action<IDynamicComponentMapper<TComponent>> mapping) where TComponent : class;
4646

4747
void Component<TComponent>(string notVisiblePropertyOrFieldName,
4848
Action<IComponentMapper<TComponent>> mapping) where TComponent : class;
@@ -57,7 +57,7 @@ void Component<TComponent>(string notVisiblePropertyOrFieldName,
5757

5858
public interface IPlainPropertyContainerMapper<TContainer> : IBasePlainPropertyContainerMapper<TContainer>
5959
{
60-
void OneToOne<TProperty>(Expression<Func<TContainer, TProperty>> property, Action<IOneToOneMapper> mapping) where TProperty : class;
61-
void OneToOne<TProperty>(string notVisiblePropertyOrFieldName, Action<IOneToOneMapper> mapping) where TProperty : class;
60+
void OneToOne<TProperty>(Expression<Func<TContainer, TProperty>> property, Action<IOneToOneMapper<TProperty>> mapping) where TProperty : class;
61+
void OneToOne<TProperty>(string notVisiblePropertyOrFieldName, Action<IOneToOneMapper<TProperty>> mapping) where TProperty : class;
6262
}
6363
}

src/NHibernate/Mapping/ByCode/Impl/AbstractPropertyContainerMapper.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ protected AbstractPropertyContainerMapper(System.Type container, HbmMapping mapD
1313
public virtual void OneToOne(MemberInfo property, Action<IOneToOneMapper> mapping)
1414
{
1515
var hbm = new HbmOneToOne {name = property.Name};
16-
mapping(new OneToOneMapper(property, hbm));
16+
var type = typeof(OneToOneMapper<>).MakeGenericType(property.GetPropertyOrFieldType());
17+
var mapper = (IOneToOneMapper)Activator.CreateInstance(type, property, hbm);
18+
mapping(mapper);
1719
AddProperty(hbm);
1820
}
1921

@@ -48,7 +50,7 @@ public virtual void List(MemberInfo property, Action<IListPropertiesMapper> coll
4850
}
4951

5052
public virtual void Map(MemberInfo property, Action<IMapPropertiesMapper> collectionMapping,
51-
Action<IMapKeyRelation> keyMapping, Action<ICollectionElementRelation> mapping)
53+
Action<IMapKeyRelation> keyMapping, Action<ICollectionElementRelation> mapping)
5254
{
5355
var hbm = new HbmMap {name = property.Name};
5456
System.Type propertyType = property.GetPropertyOrFieldType();

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

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ protected void RegistePropertyMapping(Action<IPropertyMapper> mapping, params Me
7070
}
7171

7272
public void Component<TComponent>(Expression<Func<TEntity, TComponent>> property,
73-
Action<IComponentMapper<TComponent>> mapping) where TComponent : class
73+
Action<IComponentMapper<TComponent>> mapping) where TComponent : class
7474
{
7575
RegisterComponentMapping(property, mapping);
7676
}
@@ -148,20 +148,33 @@ public void ManyToOne<TProperty>(Expression<Func<TEntity, TProperty>> property)
148148
ManyToOne(property, x => { });
149149
}
150150

151-
public void OneToOne<TProperty>(Expression<Func<TEntity, TProperty>> property, Action<IOneToOneMapper> mapping)
151+
public void OneToOne<TProperty>(Expression<Func<TEntity, TProperty>> property, Action<IOneToOneMapper<TProperty>> mapping)
152152
where TProperty : class
153153
{
154-
MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property);
155-
MemberInfo memberOf = TypeExtensions.DecodeMemberAccessExpressionOf(property);
156-
RegisterOneToOneMapping<TProperty>(mapping, member, memberOf);
154+
var member = TypeExtensions.DecodeMemberAccessExpression(property);
155+
var memberOf = TypeExtensions.DecodeMemberAccessExpressionOf(property);
156+
RegisterOneToOneMapping(mapping, member, memberOf);
157157
}
158158

159-
protected void RegisterOneToOneMapping<TProperty>(Action<IOneToOneMapper> mapping, params MemberInfo[] members)
159+
public void OneToOne<TProperty>(string notVisiblePropertyOrFieldName, Action<IOneToOneMapper<TProperty>> mapping) where TProperty : class
160+
{
161+
var member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
162+
var propertyOrFieldType = member.GetPropertyOrFieldType();
163+
if (typeof(TProperty) != propertyOrFieldType)
164+
{
165+
throw new MappingException(string.Format("Wrong relation type. For the property/field '{0}' of {1} was expected a one-to-one with {2} but was {3}",
166+
notVisiblePropertyOrFieldName, typeof (TEntity).FullName, typeof (TProperty).Name, propertyOrFieldType.Name));
167+
}
168+
var memberOf = member.GetMemberFromReflectedType(typeof(TEntity));
169+
RegisterOneToOneMapping(mapping, member, memberOf);
170+
}
171+
172+
protected void RegisterOneToOneMapping<TProperty>(Action<IOneToOneMapper<TProperty>> mapping, params MemberInfo[] members)
160173
where TProperty : class
161174
{
162175
foreach (var member in members)
163176
{
164-
CustomizersHolder.AddCustomizer(new PropertyPath(PropertyPath, member), mapping);
177+
CustomizersHolder.AddCustomizer(new PropertyPath(PropertyPath, member), (IOneToOneMapper x) => mapping((IOneToOneMapper<TProperty>) x));
165178
explicitDeclarationsHolder.AddAsOneToOneRelation(member);
166179
}
167180
}
@@ -193,8 +206,8 @@ protected void RegisterAnyMapping<TProperty>(Action<IAnyMapper> mapping, System.
193206
}
194207

195208
public void Set<TElement>(Expression<Func<TEntity, IEnumerable<TElement>>> property,
196-
Action<ISetPropertiesMapper<TEntity, TElement>> collectionMapping,
197-
Action<ICollectionElementRelation<TElement>> mapping)
209+
Action<ISetPropertiesMapper<TEntity, TElement>> collectionMapping,
210+
Action<ICollectionElementRelation<TElement>> mapping)
198211
{
199212
RegisterSetMapping(property, collectionMapping, mapping);
200213
}
@@ -222,8 +235,8 @@ protected void RegisterSetMapping<TElement>(Action<ISetPropertiesMapper<TEntity,
222235
}
223236

224237
public void Bag<TElement>(Expression<Func<TEntity, IEnumerable<TElement>>> property,
225-
Action<IBagPropertiesMapper<TEntity, TElement>> collectionMapping,
226-
Action<ICollectionElementRelation<TElement>> mapping)
238+
Action<IBagPropertiesMapper<TEntity, TElement>> collectionMapping,
239+
Action<ICollectionElementRelation<TElement>> mapping)
227240
{
228241
RegisterBagMapping(property, collectionMapping, mapping);
229242
}
@@ -250,8 +263,8 @@ protected void RegisterBagMapping<TElement>(Action<IBagPropertiesMapper<TEntity,
250263
}
251264

252265
public void List<TElement>(Expression<Func<TEntity, IEnumerable<TElement>>> property,
253-
Action<IListPropertiesMapper<TEntity, TElement>> collectionMapping,
254-
Action<ICollectionElementRelation<TElement>> mapping)
266+
Action<IListPropertiesMapper<TEntity, TElement>> collectionMapping,
267+
Action<ICollectionElementRelation<TElement>> mapping)
255268
{
256269
RegisterListMapping(property, collectionMapping, mapping);
257270
}
@@ -278,9 +291,9 @@ protected void RegisterListMapping<TElement>(Action<IListPropertiesMapper<TEntit
278291
}
279292

280293
public void Map<TKey, TElement>(Expression<Func<TEntity, IDictionary<TKey, TElement>>> property,
281-
Action<IMapPropertiesMapper<TEntity, TKey, TElement>> collectionMapping,
282-
Action<IMapKeyRelation<TKey>> keyMapping,
283-
Action<ICollectionElementRelation<TElement>> mapping)
294+
Action<IMapPropertiesMapper<TEntity, TKey, TElement>> collectionMapping,
295+
Action<IMapKeyRelation<TKey>> keyMapping,
296+
Action<ICollectionElementRelation<TElement>> mapping)
284297
{
285298
RegisterMapMapping(property, collectionMapping, keyMapping, mapping);
286299
}
@@ -351,7 +364,7 @@ public void Set<TElement>(string notVisiblePropertyOrFieldName, Action<ISetPrope
351364
if(!typeof(TElement).Equals(collectionElementType))
352365
{
353366
throw new MappingException(string.Format("Wrong collection element type. For the property/field '{0}' of {1} was expected a collection of {2} but was {3}",
354-
notVisiblePropertyOrFieldName, typeof (TEntity).FullName, typeof (TElement).Name, collectionElementType.Name));
367+
notVisiblePropertyOrFieldName, typeof (TEntity).FullName, typeof (TElement).Name, collectionElementType.Name));
355368
}
356369
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TEntity));
357370
RegisterSetMapping<TElement>(collectionMapping, mapping, member, memberOf);
@@ -492,19 +505,6 @@ public void Any<TProperty>(string notVisiblePropertyOrFieldName, System.Type idT
492505
RegisterAnyMapping<TProperty>(mapping, idTypeOfMetaType, member, memberOf);
493506
}
494507

495-
public void OneToOne<TProperty>(string notVisiblePropertyOrFieldName, Action<IOneToOneMapper> mapping) where TProperty : class
496-
{
497-
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
498-
var propertyOrFieldType = member.GetPropertyOrFieldType();
499-
if (!typeof(TProperty).Equals(propertyOrFieldType))
500-
{
501-
throw new MappingException(string.Format("Wrong relation type. For the property/field '{0}' of {1} was expected a one-to-one with {2} but was {3}",
502-
notVisiblePropertyOrFieldName, typeof(TEntity).FullName, typeof(TProperty).Name, propertyOrFieldType.Name));
503-
}
504-
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TEntity));
505-
RegisterOneToOneMapping<TProperty>(mapping, member, memberOf);
506-
}
507-
508508
public static MemberInfo GetPropertyOrFieldMatchingNameOrThrow(string memberName)
509509
{
510510
var result = typeof(TEntity).GetPropertyOrFieldMatchingName(memberName);

src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ protected void AddProperty(object property)
4242
public void Property(MemberInfo property, Action<IPropertyMapper> mapping)
4343
{
4444
var hbmProperty = new HbmProperty
45-
{
46-
name = property.Name,
45+
{
46+
name = property.Name,
4747
type1 = property.GetPropertyOrFieldType().GetNhTypeName()
48-
};
48+
};
4949

5050
mapping(new PropertyMapper(property, hbmProperty, new NoMemberPropertyMapper()));
5151
AddProperty(hbmProperty);
@@ -82,7 +82,10 @@ public void Any(MemberInfo property, System.Type idTypeOfMetaType, Action<IAnyMa
8282
public void OneToOne(MemberInfo property, Action<IOneToOneMapper> mapping)
8383
{
8484
var hbm = new HbmOneToOne { name = property.Name };
85-
mapping(new OneToOneMapper(property, new NoMemberPropertyMapper(), hbm));
85+
86+
var type = typeof (OneToOneMapper<>).MakeGenericType(property.GetPropertyOrFieldType());
87+
var mapper = (IOneToOneMapper) Activator.CreateInstance(type, property, new NoMemberPropertyMapper(), hbm);
88+
mapping(mapper);
8689
AddProperty(hbm);
8790
}
8891

src/NHibernate/Mapping/ByCode/Impl/OneToOneMapper.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq.Expressions;
23
using System.Reflection;
34
using NHibernate.Cfg.MappingSchema;
45

@@ -115,4 +116,22 @@ public void ForeignKey(string foreignKeyName)
115116

116117
#endregion
117118
}
119+
120+
public class OneToOneMapper<T> : OneToOneMapper, IOneToOneMapper<T>
121+
{
122+
public OneToOneMapper(MemberInfo member, HbmOneToOne oneToOne)
123+
: base(member, oneToOne)
124+
{
125+
}
126+
127+
public OneToOneMapper(MemberInfo member, IAccessorPropertyMapper accessorMapper, HbmOneToOne oneToOne)
128+
: base(member, accessorMapper, oneToOne)
129+
{
130+
}
131+
132+
public void PropertyReference<TProperty>(Expression<Func<T, TProperty>> reference)
133+
{
134+
PropertyReference(TypeExtensions.DecodeMemberAccessExpression(reference));
135+
}
136+
}
118137
}

0 commit comments

Comments
 (0)