Skip to content

Commit 47bb7ee

Browse files
jeff-hagenJeff Hagen
andauthored
Allow specification of tuplizers for components and subclasses (#727)
Fixes #749 +semver:feature --------- Co-authored-by: Jeff Hagen <[email protected]>
1 parent 090f834 commit 47bb7ee

File tree

14 files changed

+142
-17
lines changed

14 files changed

+142
-17
lines changed

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using NUnit.Framework;
1+
using System;
2+
using FluentNHibernate.MappingModel;
3+
using NUnit.Framework;
24

35
namespace FluentNHibernate.Testing.DomainModel.Mapping;
46

@@ -103,6 +105,34 @@ public void ComponentSetsClass()
103105
.ForMapping(m =>
104106
m.Component(x => x.Component, c => c.Map(x => x.Name)))
105107
.Element("class/component").HasAttribute("class", typeof(ComponentTarget).AssemblyQualifiedName);
106-
}
108+
}
107109

110+
[Test]
111+
public void ComponentCanSetTuplizer()
112+
{
113+
Type tuplizerType = typeof(NHibernate.Tuple.Entity.PocoEntityTuplizer);
114+
new MappingTester<PropertyTarget>()
115+
.ForMapping(m =>
116+
m.Component(x => x.Component, c => c.Tuplizer(TuplizerMode.Poco, tuplizerType)))
117+
.Element("class/component/tuplizer")
118+
.HasAttribute("class", tuplizerType.AssemblyQualifiedName)
119+
.HasAttribute("entity-mode", nameof(TuplizerMode.Poco).ToLower());
120+
}
121+
122+
[Test]
123+
public void ComponentCanSetTuplizerInCorrectOrderRegardlessOfDeclaration()
124+
{
125+
Type tuplizerType = typeof(NHibernate.Tuple.Entity.PocoEntityTuplizer);
126+
new MappingTester<PropertyTarget>()
127+
.ForMapping(m =>
128+
m.Component(x => x.Component, c =>
129+
{
130+
c.Map(x => x.Name);
131+
c.ParentReference(x => x.MyParent);
132+
c.Tuplizer(TuplizerMode.Poco, tuplizerType);
133+
}))
134+
.Element("class/component/tuplizer").Exists().ShouldBeInParentAtPosition(0)
135+
.Element("class/component/parent").Exists().ShouldBeInParentAtPosition(1)
136+
.Element("class/component/property").Exists().ShouldBeInParentAtPosition(2);
137+
}
108138
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public virtual MappingTester<T> ShouldBeInParentAtPosition(int elementPosition)
189189
else
190190
{
191191
XmlElement elementAtPosition = (XmlElement)currentElement.ParentNode.ChildNodes.Item(elementPosition);
192-
Assert.That(elementAtPosition, Is.EqualTo(currentElement), $"Expected '{currentElement.Name}' but was '{elementAtPosition.Name}'");
192+
Assert.That(elementAtPosition, Is.SameAs(currentElement), $"Expected '{currentElement.Name}' but was '{elementAtPosition.Name}'");
193193
}
194194

195195
return this;

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
using System;
12
using FluentNHibernate.Conventions;
23
using FluentNHibernate.Conventions.Instances;
34
using FluentNHibernate.Mapping;
5+
using FluentNHibernate.MappingModel;
46
using NUnit.Framework;
57

68
namespace FluentNHibernate.Testing.DomainModel.Mapping;
@@ -590,7 +592,28 @@ public void SubSubclassOneToManyReferenceHasConventionApplied()
590592
.HasAttribute("foreign-key", "test_fk");
591593

592594
}
593-
595+
596+
[Test]
597+
public void SubclassCanSetTuplizerInCorrectOrder()
598+
{
599+
Type tuplizerType = typeof(NHibernate.Tuple.Entity.PocoEntityTuplizer);
600+
new MappingTester<MappedObject>()
601+
.SubClassMapping<MappedObjectSubclass>(m =>
602+
{
603+
m.Map(x => x.SubclassProperty);
604+
m.Tuplizer(TuplizerMode.Poco, tuplizerType);
605+
m.DiscriminatorValue("test");
606+
})
607+
.ForMapping(m =>
608+
{
609+
m.DiscriminateSubClassesOnColumn("test_column");
610+
m.Id(x => x.Id);
611+
m.Tuplizer(TuplizerMode.Poco, tuplizerType);
612+
})
613+
.Element("class/subclass/tuplizer").Exists().ShouldBeInParentAtPosition(0)
614+
.Element("class/tuplizer").Exists().ShouldBeInParentAtPosition(0);
615+
}
616+
594617
public class TestPropertyConvention : IPropertyConvention
595618
{
596619
public void Apply(IPropertyInstance instance)

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using FluentNHibernate.MappingModel;
13
using NUnit.Framework;
24

35
namespace FluentNHibernate.Testing.DomainModel.Mapping;
@@ -44,4 +46,24 @@ public void ShouldAllowEntityNameToBeSetOnUnionSubclasses()
4446
}).Element("class/union-subclass")
4547
.HasAttribute("entity-name", "name");
4648
}
49+
50+
[Test]
51+
public void SubclassCanSetTuplizerInCorrectOrder()
52+
{
53+
Type tuplizerType = typeof(NHibernate.Tuple.Entity.PocoEntityTuplizer);
54+
new MappingTester<MappedObject>()
55+
.SubClassMapping<MappedObjectSubclass>(m =>
56+
{
57+
m.Map(x => x.SubclassProperty);
58+
m.Tuplizer(TuplizerMode.Poco, tuplizerType);
59+
})
60+
.ForMapping(m =>
61+
{
62+
m.UseUnionSubclassForInheritanceMapping();
63+
m.Id(x => x.Id);
64+
m.Tuplizer(TuplizerMode.Poco, tuplizerType);
65+
})
66+
.Element("class/union-subclass/tuplizer").Exists().ShouldBeInParentAtPosition(0)
67+
.Element("class/tuplizer").Exists().ShouldBeInParentAtPosition(0);
68+
}
4769
}

src/FluentNHibernate/Mapping/ClassMap.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -583,17 +583,8 @@ public ClassMap<T> ApplyFilter(string name)
583583
/// </summary>
584584
/// <param name="mode">Tuplizer entity-mode</param>
585585
/// <param name="tuplizerType">Tuplizer type</param>
586-
public TuplizerPart Tuplizer(TuplizerMode mode, Type tuplizerType)
587-
{
588-
providers.TuplizerMapping = new TuplizerMapping();
589-
providers.TuplizerMapping.Set(x => x.Mode, Layer.UserSupplied, mode);
590-
providers.TuplizerMapping.Set(x => x.Type, Layer.UserSupplied, new TypeReference(tuplizerType));
591-
592-
return new TuplizerPart(providers.TuplizerMapping)
593-
.Type(tuplizerType)
594-
.Mode(mode);
595-
}
596-
586+
public TuplizerPart Tuplizer(TuplizerMode mode, Type tuplizerType) => CreateTuplizerPart(mode, tuplizerType);
587+
597588
ClassMapping IMappingProvider.GetClassMapping()
598589
{
599590
var mapping = new ClassMapping(attributes.Clone());

src/FluentNHibernate/Mapping/ClasslikeMapBase.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq.Expressions;
55
using FluentNHibernate.Mapping.Providers;
6+
using FluentNHibernate.MappingModel;
67
using FluentNHibernate.Utils;
78

89
namespace FluentNHibernate.Mapping;
@@ -438,6 +439,17 @@ protected StoredProcedurePart StoredProcedure(string element, string innerText)
438439
providers.StoredProcedures.Add(part);
439440
return part;
440441
}
442+
443+
protected TuplizerPart CreateTuplizerPart(TuplizerMode mode, Type tuplizerType)
444+
{
445+
providers.TuplizerMapping = new TuplizerMapping();
446+
providers.TuplizerMapping.Set(x => x.Mode, Layer.UserSupplied, mode);
447+
providers.TuplizerMapping.Set(x => x.Type, Layer.UserSupplied, new TypeReference(tuplizerType));
448+
449+
return new TuplizerPart(providers.TuplizerMapping)
450+
.Type(tuplizerType)
451+
.Mode(mode);
452+
}
441453

442454
internal IEnumerable<IPropertyMappingProvider> Properties => providers.Properties;
443455

src/FluentNHibernate/Mapping/ComponentPart.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public ComponentPart<T> LazyLoad()
4141
nextBool = true;
4242
return this;
4343
}
44+
45+
/// <summary>
46+
/// Configures the tuplizer for this component. The tuplizer defines how to transform
47+
/// a Property-Value to its persistent representation, and viceversa a Column-Value
48+
/// to its in-memory representation, and the EntityMode defines which tuplizer is in use.
49+
/// </summary>
50+
/// <param name="mode">Tuplizer entity-mode</param>
51+
/// <param name="tuplizerType">Tuplizer type</param>
52+
public TuplizerPart Tuplizer(TuplizerMode mode, Type tuplizerType) => CreateTuplizerPart(mode, tuplizerType);
4453

4554
IComponentMapping IComponentMappingProvider.GetComponentMapping()
4655
{

src/FluentNHibernate/Mapping/ComponentPartBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ protected ComponentMapping CreateComponentMapping()
167167
if (member is not null)
168168
mapping.Set(x => x.Name, Layer.Defaults, member.Name);
169169

170+
mapping.Set(x => x.Tuplizer, Layer.UserSupplied, providers.TuplizerMapping);
171+
170172
foreach (var property in providers.Properties)
171173
mapping.AddProperty(property.GetPropertyMapping());
172174

src/FluentNHibernate/Mapping/SubClassPart.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using FluentNHibernate.Mapping.Providers;
55
using FluentNHibernate.MappingModel;
66
using FluentNHibernate.MappingModel.ClassBased;
7-
using FluentNHibernate.Utils;
87

98
namespace FluentNHibernate.Mapping;
109

src/FluentNHibernate/Mapping/SubclassMap.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,15 @@ public void Extends(Type type)
277277
{
278278
attributes.Set("Extends", Layer.UserSupplied, type);
279279
}
280+
281+
/// <summary>
282+
/// Configures the tuplizer for this entity. The tuplizer defines how to transform
283+
/// a Property-Value to its persistent representation, and viceversa a Column-Value
284+
/// to its in-memory representation, and the EntityMode defines which tuplizer is in use.
285+
/// </summary>
286+
/// <param name="mode">Tuplizer entity-mode</param>
287+
/// <param name="tuplizerType">Tuplizer type</param>
288+
public TuplizerPart Tuplizer(TuplizerMode mode, Type tuplizerType) => CreateTuplizerPart(mode, tuplizerType);
280289

281290
SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(SubclassType type)
282291
{
@@ -330,6 +339,9 @@ SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(Subclas
330339
case MappingProviderStore.ProviderType.StoredProcedure:
331340
mapping.AddStoredProcedure(((IStoredProcedureMappingProvider)mappingProviderObj).GetStoredProcedureMapping());
332341
break;
342+
case MappingProviderStore.ProviderType.Tupilizer:
343+
mapping.Set(y => y.Tuplizer, Layer.Defaults, (TuplizerMapping)mappingProviderObj);
344+
break;
333345
case MappingProviderStore.ProviderType.Subclass:
334346
case MappingProviderStore.ProviderType.Filter:
335347
case MappingProviderStore.ProviderType.Join:
@@ -338,7 +350,6 @@ SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(Subclas
338350
case MappingProviderStore.ProviderType.NaturalId:
339351
case MappingProviderStore.ProviderType.Version:
340352
case MappingProviderStore.ProviderType.Discriminator:
341-
case MappingProviderStore.ProviderType.Tupilizer:
342353
default:
343354
throw new Exception("Internal Error");
344355
}

0 commit comments

Comments
 (0)