Skip to content

Commit 36f20e4

Browse files
ByronPogsonfredericDelaporte
authored andcommitted
NH-3993 - Component: ability to map non-public parents and composite element relations
* NH-3993 IComponentElementMapper now also extends IMinimalPlainPropertyContainerMapper Add method to IComponentAttributesMapper<TComponent> to allow for non-public parent * NH-3993 Add private Components to Component Elements
1 parent 21007cc commit 36f20e4

File tree

8 files changed

+281
-12
lines changed

8 files changed

+281
-12
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace NHibernate.Test.NHSpecificTest.NH3993
5+
{
6+
public class BaseEntity
7+
{
8+
public virtual Guid Id { get; set; }
9+
private HierarchicalComponent _component;
10+
public virtual HierarchicalComponent Component
11+
{
12+
get => _component;
13+
set => _component = value;
14+
}
15+
}
16+
17+
public class HierarchicalComponent
18+
{
19+
// Covers Parent added to Component Customizer for not visible parents
20+
private HierarchicalComponent _parent;
21+
public virtual HierarchicalComponent Parent
22+
{
23+
get => _parent;
24+
set => _parent = value;
25+
}
26+
27+
// Element to cover Componenent Element Customiser
28+
private IDictionary<string,Element> _elements = new Dictionary<string,Element>();
29+
public IEnumerable<Element> Elements => _elements.Values;
30+
}
31+
32+
public class SimpleComponent
33+
{
34+
public virtual string SimpleComponentName { get; set; }
35+
}
36+
37+
public class Element
38+
{
39+
// To cover added Property in Componenent Element Customiser
40+
private string _name;
41+
public virtual string Name
42+
{
43+
get => _name;
44+
set => _name = value;
45+
}
46+
47+
// To cover added Component Component Element Customiser
48+
private SimpleComponent _component;
49+
50+
public virtual SimpleComponent Component
51+
{
52+
get => _component;
53+
set => _component = value;
54+
}
55+
56+
// To cover added Parent in Componenent Element Customiser
57+
private Element _parent;
58+
public virtual Element Parent
59+
{
60+
get => _parent;
61+
set => _parent = Parent;
62+
}
63+
64+
private string _description;
65+
}
66+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System.Linq;
2+
using NHibernate.Cfg.MappingSchema;
3+
using NHibernate.Mapping.ByCode;
4+
using NHibernate.Test.MappingByCode.IntegrationTests.NH2825;
5+
using NUnit.Framework;
6+
7+
namespace NHibernate.Test.NHSpecificTest.NH3993
8+
{
9+
[TestFixture]
10+
public class FixtureByCode : TestCaseMappingByCode
11+
{
12+
[Test]
13+
public void Test_MapPrivateComponentProperty_MapsCorrectly()
14+
{
15+
var mapper = new ModelMapper();
16+
17+
mapper.AddMapping(typeof(BaseEntityMapper));
18+
var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
19+
20+
// The component
21+
var componentPropertyMapping = mapping.RootClasses[0]
22+
.Properties.SingleOrDefault(x => x.Name == "Component") as HbmComponent;
23+
Assert.IsNotNull(componentPropertyMapping, "Component did not correctly map");
24+
// Component parent
25+
Assert.IsNotNull(componentPropertyMapping.Parent, "Component did not correctly map parent");
26+
// Component element
27+
var elementListMapping = componentPropertyMapping.Properties.SingleOrDefault(p => p.Name == "_elements") as HbmMap;
28+
Assert.IsNotNull(elementListMapping, "Component did not map element list");
29+
var elementMapping = elementListMapping.ElementRelationship as HbmCompositeElement;
30+
Assert.IsNotNull(elementMapping, "Component did not map elements");
31+
// Component element property
32+
var privateProperty = elementMapping.Properties.SingleOrDefault(p => p.Name == "_name");
33+
Assert.IsNotNull(privateProperty, "Component Element did not map private property");
34+
// Component element parent
35+
Assert.IsNotNull(elementMapping.Parent, "Component Element did not map parent");
36+
// Component element relation
37+
var relationproperty = elementMapping.Properties.SingleOrDefault(p => p.Name == "_description");
38+
Assert.IsNotNull(relationproperty, "Component Element did not map one to many relationship");
39+
// Component element component
40+
var componentMapping = elementMapping.Properties.SingleOrDefault(p => p.Name == "_component");
41+
Assert.IsNotNull(componentMapping, "Component Element did not private component");
42+
43+
}
44+
45+
[Test]
46+
public void Test_InvalidPrivateProperty_ThrowsException()
47+
{
48+
var mapper = new ModelMapper();
49+
50+
Assert.Throws<MappingException>(() => mapper.AddMapping(typeof(InvalidPropertyMapper)));
51+
}
52+
53+
[Test]
54+
public void Test_ManyToOneHasInvalidType_ThrowsException()
55+
{
56+
var mapper = new ModelMapper();
57+
58+
Assert.Throws<MappingException>(() => mapper.AddMapping(typeof(InvalidRelationshipMapper)));
59+
}
60+
61+
protected override HbmMapping GetMappings()
62+
{
63+
var mapper = new ModelMapper();
64+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
65+
}
66+
}
67+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using NHibernate.Mapping.ByCode;
2+
using NHibernate.Mapping.ByCode.Conformist;
3+
4+
namespace NHibernate.Test.NHSpecificTest.NH3993
5+
{
6+
public class BaseEntityMapper : ClassMapping<BaseEntity>
7+
{
8+
#region Constructors
9+
10+
public BaseEntityMapper()
11+
{
12+
Component(c => c.Component,
13+
m =>
14+
{
15+
m.Parent("_parent",
16+
p => p.Access(Accessor.NoSetter));
17+
m.Map<string, Element>("_elements",
18+
map => map.Table("Elements"),
19+
key => key.Element(element => element.Formula("Key")),
20+
rel => rel.Component(e =>
21+
{
22+
e.Property("_name",
23+
p => p.Column("Name"));
24+
e.Parent("_parent",
25+
p => p.Access(Accessor.NoSetter));
26+
e.ManyToOne<string>("_description",
27+
r => r.Column("Desc"));
28+
e.Component<SimpleComponent>("_component",
29+
c => c.Property("SimpleComponentName",
30+
p => p.Column("SimpleComponentName")));
31+
}));
32+
});
33+
}
34+
35+
#endregion
36+
}
37+
38+
public class InvalidPropertyMapper : ClassMapping<BaseEntity>
39+
{
40+
#region Constructors
41+
42+
public InvalidPropertyMapper()
43+
{
44+
Component(c => c.Component,
45+
m =>
46+
{
47+
m.Map<string, Element>("_elements",
48+
map => map.Table("Elements"),
49+
key => key.Element(element => element.Formula("Key")),
50+
rel => rel.Component(e =>
51+
{
52+
e.Property("Non existent field",
53+
p => p.Column("Name"));
54+
}));
55+
});
56+
}
57+
58+
#endregion
59+
}
60+
61+
public class InvalidRelationshipMapper : ClassMapping<BaseEntity>
62+
{
63+
#region Constructors
64+
65+
public InvalidRelationshipMapper()
66+
{
67+
Component(c => c.Component,
68+
m =>
69+
{
70+
m.Map<string, Element>("_elements",
71+
map => map.Table("Elements"),
72+
key => key.Element(element => element.Formula("Key")),
73+
rel => rel.Component(e =>
74+
{
75+
e.ManyToOne<Element>("_description",
76+
r => r.Column("Desc"));
77+
}));
78+
});
79+
}
80+
81+
#endregion
82+
}
83+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,9 @@
975975
<Compile Include="NHSpecificTest\NH3909\FixtureByCode.cs" />
976976
<Compile Include="NHSpecificTest\NH3957\ResultTransformerEqualityFixture.cs" />
977977
<Compile Include="NHSpecificTest\NH3956\Fixture.cs" />
978+
<Compile Include="NHSpecificTest\NH3993\Entities.cs" />
979+
<Compile Include="NHSpecificTest\NH3993\Fixture.cs" />
980+
<Compile Include="NHSpecificTest\NH3993\Mappers.cs" />
978981
<Compile Include="NHSpecificTest\NH3755\Circle.cs" />
979982
<Compile Include="NHSpecificTest\NH3755\Fixture.cs" />
980983
<Compile Include="NHSpecificTest\NH3755\ICircle.cs" />

src/NHibernate/Mapping/ByCode/IComponentElementMapper.cs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,19 @@
44

55
namespace NHibernate.Mapping.ByCode
66
{
7-
public interface IComponentElementMapper : IComponentAttributesMapper
7+
public interface IComponentElementMapper : IComponentAttributesMapper, IMinimalPlainPropertyContainerMapper
88
{
9-
void Property(MemberInfo property, Action<IPropertyMapper> mapping);
10-
119
void Component(MemberInfo property, Action<IComponentElementMapper> mapping);
12-
13-
void ManyToOne(MemberInfo property, Action<IManyToOneMapper> mapping);
1410
}
1511

16-
public interface IComponentElementMapper<TComponent> : IComponentAttributesMapper<TComponent>
12+
public interface IComponentElementMapper<TComponent> : IComponentAttributesMapper<TComponent>, IMinimalPlainPropertyContainerMapper<TComponent>
1713
{
18-
void Property<TProperty>(Expression<Func<TComponent, TProperty>> property, Action<IPropertyMapper> mapping);
19-
void Property<TProperty>(Expression<Func<TComponent, TProperty>> property);
20-
2114
void Component<TNestedComponent>(Expression<Func<TComponent, TNestedComponent>> property,
22-
Action<IComponentElementMapper<TNestedComponent>> mapping)
15+
Action<IComponentElementMapper<TNestedComponent>> mapping)
2316
where TNestedComponent : class;
2417

25-
void ManyToOne<TProperty>(Expression<Func<TComponent, TProperty>> property, Action<IManyToOneMapper> mapping) where TProperty : class;
26-
void ManyToOne<TProperty>(Expression<Func<TComponent, TProperty>> property) where TProperty : class;
18+
void Component<TNestedComponent>(string notVisiblePropertyOrFieldName,
19+
Action<IComponentElementMapper<TNestedComponent>> mapping)
20+
where TNestedComponent : class;
2721
}
2822
}

src/NHibernate/Mapping/ByCode/IComponentMapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public interface IComponentAttributesMapper<TComponent> : IEntityPropertyMapper
2121
{
2222
void Parent<TProperty>(Expression<Func<TComponent, TProperty>> parent) where TProperty : class;
2323
void Parent<TProperty>(Expression<Func<TComponent, TProperty>> parent, Action<IComponentParentMapper> parentMapping) where TProperty : class;
24+
void Parent(string notVisiblePropertyOrFieldName, Action<IComponentParentMapper> mapping);
2425
void Update(bool consideredInUpdateQuery);
2526
void Insert(bool consideredInInsertQuery);
2627
void Lazy(bool isLazy);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public void Parent<TProperty>(Expression<Func<TComponent, TProperty>> parent) wh
3737
Parent(parent, x => { });
3838
}
3939

40+
public void Parent(string notVisiblePropertyOrFieldName, Action<IComponentParentMapper> parentMapping)
41+
{
42+
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
43+
AddCustomizer(m => m.Parent(member, parentMapping));
44+
}
45+
4046
public void Parent<TProperty>(Expression<Func<TComponent, TProperty>> parent, Action<IComponentParentMapper> parentMapping) where TProperty : class
4147
{
4248
MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(parent);

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ public ComponentElementCustomizer(IModelExplicitDeclarationsHolder explicitDecla
3131

3232
#region IComponentElementMapper<TComponent> Members
3333

34+
public void Parent(string notVisiblePropertyOrFieldName, Action<IComponentParentMapper> parentMapping)
35+
{
36+
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
37+
_customizersHolder.AddCustomizer(typeof(TComponent), (IComponentAttributesMapper x) => x.Parent(member, parentMapping));
38+
_explicitDeclarationsHolder.AddAsPersistentMember(member);
39+
}
40+
3441
public void Parent<TProperty>(Expression<Func<TComponent, TProperty>> parent) where TProperty : class
3542
{
3643
Parent(parent, x => { });
@@ -68,6 +75,25 @@ public void Class<TConcrete>() where TConcrete : TComponent
6875
_customizersHolder.AddCustomizer(typeof (TComponent), (IComponentAttributesMapper x) => x.Class(typeof (TConcrete)));
6976
}
7077

78+
public void Property(string notVisiblePropertyOrFieldName, Action<IPropertyMapper> mapping)
79+
{
80+
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
81+
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TComponent));
82+
_customizersHolder.AddCustomizer(new PropertyPath(_propertyPath, member), mapping);
83+
_explicitDeclarationsHolder.AddAsProperty(memberOf);
84+
}
85+
86+
public static MemberInfo GetPropertyOrFieldMatchingNameOrThrow(string memberName)
87+
{
88+
var result = typeof(TComponent).GetPropertyOrFieldMatchingName(memberName);
89+
if (result == null)
90+
{
91+
throw new MappingException(string.Format("Member not found. The member '{0}' does not exists in type {1}", memberName, typeof(TComponent).FullName));
92+
}
93+
return result;
94+
}
95+
96+
7197
public void Property<TProperty>(Expression<Func<TComponent, TProperty>> property, Action<IPropertyMapper> mapping)
7298
{
7399
MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property);
@@ -92,6 +118,15 @@ public void Component<TNestedComponent>(Expression<Func<TComponent, TNestedCompo
92118
mapping(new ComponentElementCustomizer<TNestedComponent>(_explicitDeclarationsHolder, new PropertyPath(_propertyPath, memberOf), _customizersHolder));
93119
}
94120

121+
public void Component<TNestedComponent>(string notVisiblePropertyOrFieldName, Action<IComponentElementMapper<TNestedComponent>> mapping)
122+
where TNestedComponent : class
123+
{
124+
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
125+
mapping(new ComponentElementCustomizer<TNestedComponent>(_explicitDeclarationsHolder, new PropertyPath(_propertyPath, member), _customizersHolder));
126+
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TComponent));
127+
mapping(new ComponentElementCustomizer<TNestedComponent>(_explicitDeclarationsHolder, new PropertyPath(_propertyPath, memberOf), _customizersHolder));
128+
}
129+
95130
public void ManyToOne<TProperty>(Expression<Func<TComponent, TProperty>> property, Action<IManyToOneMapper> mapping) where TProperty : class
96131
{
97132
MemberInfo member = TypeExtensions.DecodeMemberAccessExpression(property);
@@ -107,6 +142,20 @@ public void ManyToOne<TProperty>(Expression<Func<TComponent, TProperty>> propert
107142
ManyToOne(property, x => { });
108143
}
109144

145+
public void ManyToOne<TProperty>(string notVisiblePropertyOrFieldName, Action<IManyToOneMapper> mapping) where TProperty : class
146+
{
147+
MemberInfo member = GetPropertyOrFieldMatchingNameOrThrow(notVisiblePropertyOrFieldName);
148+
var propertyOrFieldType = member.GetPropertyOrFieldType();
149+
if (!typeof(TProperty).Equals(propertyOrFieldType))
150+
{
151+
throw new MappingException(string.Format("Wrong relation type. For the property/field '{0}' of {1} was expected a many-to-one with {2} but was {3}",
152+
notVisiblePropertyOrFieldName, typeof(TComponent).FullName, typeof(TProperty).Name, propertyOrFieldType.Name));
153+
}
154+
MemberInfo memberOf = member.GetMemberFromReflectedType(typeof(TComponent));
155+
_explicitDeclarationsHolder.AddAsManyToOneRelation(member);
156+
_explicitDeclarationsHolder.AddAsManyToOneRelation(memberOf);
157+
}
158+
110159
public void Access(Accessor accessor)
111160
{
112161
_customizersHolder.AddCustomizer(typeof (TComponent), (IComponentAttributesMapper x) => x.Access(accessor));

0 commit comments

Comments
 (0)