Skip to content

Commit 21bef40

Browse files
committed
Add ability to specify access for parent references in components
Fixes #120 +semver:breaking
1 parent 7b10309 commit 21bef40

File tree

8 files changed

+91
-5
lines changed

8 files changed

+91
-5
lines changed

src/FluentNHibernate.Testing/DomainModel/Mapping/ComponentElementPartTester.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ public void CanIncludeParentReference()
2121
.HasAttribute("name", "MyParent");
2222
}
2323

24+
[Test]
25+
public void CanSetParentReferenceAccess()
26+
{
27+
new MappingTester<PropertyTarget>()
28+
.ForMapping(m =>
29+
m.HasMany(x => x.Components)
30+
.Component(c =>
31+
{
32+
c.Map(x => x.Name);
33+
c.ParentReference(x => x.MyParent, FluentNHibernate.Mapping.Access.BackField);
34+
}))
35+
.Element("class/bag/composite-element/parent").Exists()
36+
.HasAttribute("name", "MyParent")
37+
.HasAttribute("access", "backfield");
38+
}
39+
2440
[Test]
2541
public void CanCreateNestedCompositeElement()
2642
{

src/FluentNHibernate.Testing/DomainModel/Mapping/ComponentPartTester.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ public void ComponentCanIncludeParentReference()
1919
.HasAttribute("name", "MyParent");
2020
}
2121

22+
[Test]
23+
public void ComponentCanSetParentReferenceAccessStrategy()
24+
{
25+
new MappingTester<PropertyTarget>()
26+
.ForMapping(m =>
27+
m.Component(x => x.Component, c =>
28+
{
29+
c.Map(x => x.Name);
30+
c.ParentReference(x => x.MyParent, FluentNHibernate.Mapping.Access.BackField);
31+
}))
32+
.Element("class/component/parent").ShouldBeInParentAtPosition(0)
33+
.HasAttribute("name", "MyParent")
34+
.HasAttribute("access", "backfield");
35+
}
36+
2237
[Test]
2338
public void ComponentDoesntHaveUniqueAttributeByDefault()
2439
{
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
using FluentNHibernate.Mapping;
2+
13
namespace FluentNHibernate.Conventions.Inspections
24
{
35
public interface IParentInspector : IInspector
46
{
57
string Name { get; }
8+
Access Access { get; }
69
}
710
}

src/FluentNHibernate/Conventions/Inspections/ParentInspector.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using System.Reflection;
2+
using FluentNHibernate.Mapping;
33
using FluentNHibernate.MappingModel;
44

55
namespace FluentNHibernate.Conventions.Inspections
@@ -33,5 +33,10 @@ public string Name
3333
{
3434
get { return mapping.Name; }
3535
}
36+
37+
public Access Access
38+
{
39+
get { return Access.FromString(mapping.Access); }
40+
}
3641
}
3742
}

src/FluentNHibernate/Mapping/ComponentPartBase.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,34 @@ public AccessStrategyBuilder<TBuilder> Access
5959
/// </example>
6060
public TBuilder ParentReference(Expression<Func<TEntity, object>> expression)
6161
{
62-
return ParentReference(expression.ToMember());
62+
var property = expression.ToMember();
63+
return ParentReference(property, MemberAccessResolver.Resolve(property));
6364
}
6465

65-
private TBuilder ParentReference(Member property)
66+
/// <summary>
67+
/// Specify a parent reference for this component
68+
/// </summary>
69+
/// <param name="expression">Parent property</param>
70+
/// <param name="access">Access to parent property</param>
71+
/// <example>
72+
/// ParentReference(x => x.Parent, Access.Backfield);
73+
/// </example>
74+
public TBuilder ParentReference(Expression<Func<TEntity, object>> expression, Access access)
75+
{
76+
return ParentReference(expression.ToMember(), access);
77+
}
78+
79+
TBuilder ParentReference(Member property, Access access)
6680
{
6781
var parentMapping = new ParentMapping
6882
{
6983
ContainingEntityType = typeof(TEntity)
7084
};
7185
parentMapping.Set(x => x.Name, Layer.Defaults, property.Name);
86+
87+
if (access != Mapping.Access.Property && access != Mapping.Access.Unset)
88+
parentMapping.Set(x => x.Access, Layer.Defaults, access.ToString());
89+
7290
attributes.Set("Parent", Layer.Defaults, parentMapping);
7391

7492
return (TBuilder)this;

src/FluentNHibernate/Mapping/CompositeElementPart.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,33 @@ protected virtual ManyToOnePart<TOther> References<TOther>(Member property, stri
117117
/// <param name="expression">Parent reference property</param>
118118
/// <returns>Component being mapped</returns>
119119
public void ParentReference(Expression<Func<T, object>> expression)
120+
{
121+
var property = expression.ToMember();
122+
ParentReference(property, MemberAccessResolver.Resolve(property));
123+
}
124+
125+
/// <summary>
126+
/// Maps a property of the component class as a reference back to the containing entity
127+
/// </summary>
128+
/// <param name="expression">Parent reference property</param>
129+
/// <param name="access">Access to parent reference property</param>
130+
/// <returns>Component being mapped</returns>
131+
public void ParentReference(Expression<Func<T, object>> expression, Access access)
132+
{
133+
ParentReference(expression.ToMember(), access);
134+
}
135+
136+
void ParentReference(Member property, Access access)
120137
{
121138
var parentMapping = new ParentMapping
122139
{
123140
ContainingEntityType = entity
124141
};
125-
parentMapping.Set(x => x.Name, Layer.Defaults, expression.ToMember().Name);
142+
parentMapping.Set(x => x.Name, Layer.Defaults, property.Name);
143+
144+
if (access != Access.Property && access != Access.Unset)
145+
parentMapping.Set(x => x.Access, Layer.Defaults, access.ToString());
146+
126147
attributes.Set("Parent", Layer.Defaults, parentMapping);
127148
}
128149

src/FluentNHibernate/MappingModel/Output/XmlParentWriter.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public override void ProcessParent(ParentMapping parentMapping)
2323

2424
if (parentMapping.IsSpecified("Name"))
2525
parentElement.WithAtt("name", parentMapping.Name);
26+
27+
if (parentMapping.IsSpecified("Access"))
28+
parentElement.WithAtt("access", parentMapping.Access);
2629
}
2730
}
2831
}

src/FluentNHibernate/MappingModel/ParentMapping.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ public override void AcceptVisitor(IMappingModelVisitor visitor)
2424
visitor.ProcessParent(this);
2525
}
2626

27+
public Type ContainingEntityType { get; set; }
28+
2729
public string Name
2830
{
2931
get { return attributes.GetOrDefault<string>("Name"); }
3032
}
3133

32-
public Type ContainingEntityType { get; set; }
34+
public string Access
35+
{
36+
get { return attributes.GetOrDefault<string>("Access"); }
37+
}
3338

3439
public override bool Equals(object obj)
3540
{

0 commit comments

Comments
 (0)