Skip to content

Commit 73d3409

Browse files
committed
Improve name resolver
1 parent 28a00f0 commit 73d3409

File tree

7 files changed

+194
-10
lines changed

7 files changed

+194
-10
lines changed

src/NHibernate/Cfg/Configuration.cs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using NHibernate.Id;
2424
using NHibernate.Impl;
2525
using NHibernate.Mapping;
26+
using NHibernate.Persister.Collection;
2627
using NHibernate.Proxy;
2728
using NHibernate.Tool.hbm2ddl;
2829
using NHibernate.Type;
@@ -186,16 +187,18 @@ protected void Reset()
186187
}
187188

188189
[Serializable]
189-
private class Mapping : IMapping
190+
private class Mapping : IMapping, IMetadata
190191
{
192+
private readonly IDictionary<string, NHibernate.Mapping.Collection> collections;
191193
private readonly Configuration configuration;
192194

193-
public Mapping(Configuration configuration)
195+
public Mapping(Configuration configuration, IDictionary<string, NHibernate.Mapping.Collection> collections)
194196
{
195197
this.configuration = configuration;
198+
this.collections = collections;
196199
}
197200

198-
private PersistentClass GetPersistentClass(string className)
201+
public PersistentClass GetPersistentClass(string className)
199202
{
200203
PersistentClass pc;
201204
if (!configuration.classes.TryGetValue(className, out pc))
@@ -205,6 +208,16 @@ private PersistentClass GetPersistentClass(string className)
205208
return pc;
206209
}
207210

211+
public NHibernate.Mapping.Collection GetCollection(string role)
212+
{
213+
if (collections.TryGetValue(role, out var collection))
214+
{
215+
return collection;
216+
}
217+
218+
return null;
219+
}
220+
208221
public IType GetIdentifierType(string className)
209222
{
210223
return GetPersistentClass(className).Identifier.Type;
@@ -242,7 +255,7 @@ public bool HasNonIdentifierPropertyNamedId(string className)
242255
}
243256

244257
[Serializable]
245-
private class StaticDialectMappingWrapper : IMapping
258+
private class StaticDialectMappingWrapper : IMapping, IMetadata
246259
{
247260
private readonly IMapping _mapping;
248261

@@ -273,6 +286,25 @@ public bool HasNonIdentifierPropertyNamedId(string className)
273286
}
274287

275288
public Dialect.Dialect Dialect { get; }
289+
public PersistentClass GetPersistentClass(string entityName)
290+
{
291+
if (_mapping is IMetadata metadata)
292+
{
293+
return metadata.GetPersistentClass(entityName);
294+
}
295+
296+
return null;
297+
}
298+
299+
public NHibernate.Mapping.Collection GetCollection(string role)
300+
{
301+
if (_mapping is IMetadata metadata)
302+
{
303+
return metadata.GetCollection(role);
304+
}
305+
306+
return null;
307+
}
276308
}
277309

278310
private IMapping mapping;
@@ -291,7 +323,7 @@ private void InitBlock()
291323

292324
public virtual IMapping BuildMapping()
293325
{
294-
return new Mapping(this);
326+
return new Mapping(this, collections);
295327
}
296328

297329
/// <summary>

src/NHibernate/Engine/IMetadata.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using NHibernate.Mapping;
2+
using NHibernate.Persister.Collection;
3+
4+
namespace NHibernate.Engine
5+
{
6+
public interface IMetadata : IMapping
7+
{
8+
PersistentClass GetPersistentClass(string entityName);
9+
NHibernate.Mapping.Collection GetCollection(string role);
10+
}
11+
}

src/NHibernate/Persister/Entity/AbstractPropertyMapping.cs

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using NHibernate.Cfg.XmlHbmBinding;
35
using NHibernate.Engine;
6+
using NHibernate.Mapping;
47
using NHibernate.SqlCommand;
58
using NHibernate.Type;
69
using NHibernate.Util;
@@ -12,6 +15,7 @@ namespace NHibernate.Persister.Entity
1215
/// </summary>
1316
public abstract class AbstractPropertyMapping : IPropertyMapping
1417
{
18+
private readonly HashSet<string> duplicateIncompatiblePaths = new HashSet<string>();
1519
private readonly Dictionary<string, IType> typesByPropertyPath = new Dictionary<string, IType>();
1620
private readonly Dictionary<string, string[]> columnsByPropertyPath = new Dictionary<string, string[]>();
1721
private readonly Dictionary<string, string[]> formulaTemplatesByPropertyPath = new Dictionary<string, string[]>();
@@ -91,20 +95,133 @@ public virtual string[] ToColumns(string propertyName)
9195

9296
#endregion
9397

98+
[Obsolete]
9499
protected void AddPropertyPath(string path, IType type, string[] columns, string[] formulaTemplates)
95100
{
96-
if (!typesByPropertyPath.ContainsKey(path))
101+
AddPropertyPath(path, type, columns, formulaTemplates, null);
102+
}
103+
104+
protected void AddPropertyPath(
105+
string path,
106+
IType type,
107+
string[] columns,
108+
string[] formulaTemplates,
109+
IMapping factory)
110+
{
111+
if (typesByPropertyPath.TryGetValue(path, out var existingType) || duplicateIncompatiblePaths.Contains(path))
112+
{
113+
// If types match or the new type is not an association type, there is nothing for us to do
114+
if (type == existingType || existingType == null || !(type is IAssociationType))
115+
{
116+
//TODO: Log duplicated
117+
}
118+
else if (!(existingType is IAssociationType))
119+
{
120+
// Workaround for org.hibernate.cfg.annotations.PropertyBinder.bind() adding a component for *ToOne ids
121+
//TODO: Log duplicated
122+
}
123+
else
124+
{
125+
if (type is AnyType && existingType is AnyType)
126+
{
127+
// TODO: not sure how to handle any types. For now we just return and let the first type dictate what type the property has...
128+
}
129+
else
130+
{
131+
IType commonType = null;
132+
if (type is CollectionType typeCollection && existingType is CollectionType existingCollection)
133+
{
134+
var metadata = (IMetadata) factory;
135+
var thisCollection = metadata.GetCollection(existingCollection.Role);
136+
var otherCollection = metadata.GetCollection(typeCollection.Role);
137+
138+
if (thisCollection.Equals(otherCollection))
139+
{
140+
//TODO: Log duplicated
141+
}
142+
else
143+
{
144+
//TODO: log Incompatible Registration
145+
}
146+
}
147+
else if (type is EntityType entityType1 && existingType is EntityType entityType2)
148+
{
149+
if (entityType1.GetAssociatedEntityName() == entityType2.GetAssociatedEntityName())
150+
{
151+
//TODO: Log duplicated
152+
return;
153+
}
154+
155+
commonType = GetCommonType((IMetadata)factory, entityType1, entityType2);
156+
}
157+
else
158+
{
159+
//TODO: log Incompatible Registration
160+
}
161+
162+
if (commonType == null)
163+
{
164+
duplicateIncompatiblePaths.Add(path);
165+
typesByPropertyPath.Remove(path);
166+
columnsByPropertyPath[path] = columns;
167+
168+
if ( formulaTemplates != null )
169+
{
170+
formulaTemplatesByPropertyPath[path] = formulaTemplates;
171+
}
172+
}
173+
else
174+
{
175+
typesByPropertyPath[path] = commonType;
176+
}
177+
}
178+
}
179+
}
180+
else
97181
{
98182
typesByPropertyPath[path] = type;
99183
columnsByPropertyPath[path] = columns;
100-
184+
101185
if (formulaTemplates != null)
102186
{
103187
formulaTemplatesByPropertyPath[path] = formulaTemplates;
104188
}
105189
}
106190
}
107191

192+
private static IType GetCommonType(IMetadata metadata, EntityType entityType1, EntityType entityType2)
193+
{
194+
var thisClass = metadata.GetPersistentClass(entityType1.GetAssociatedEntityName());
195+
var otherClass = metadata.GetPersistentClass(entityType2.GetAssociatedEntityName());
196+
var commonClass = GetCommonPersistent(thisClass, otherClass);
197+
198+
if (commonClass == null)
199+
{
200+
return null;
201+
}
202+
203+
switch (entityType1)
204+
{
205+
case ManyToOneType many:
206+
return new ManyToOneType(many, commonClass.EntityName);
207+
case SpecialOneToOneType special:
208+
return new SpecialOneToOneType(special, commonClass.EntityName);
209+
default:
210+
throw new Exception("Unexpected entity type: " + entityType1);
211+
212+
}
213+
}
214+
215+
private static PersistentClass GetCommonPersistent(PersistentClass class1, PersistentClass class2)
216+
{
217+
while (class2 != null && class2.MappedClass != null && !class2.MappedClass.IsAssignableFrom(class1.MappedClass))
218+
{
219+
class2 = class2.Superclass;
220+
}
221+
222+
return class2;
223+
}
224+
108225
protected internal void InitPropertyPaths( string path, IType type, string[] columns, string[] formulaTemplates, IMapping factory )
109226
{
110227
if (columns.Length != type.GetOwnerColumnSpan(factory))
@@ -136,7 +253,7 @@ protected internal void InitPropertyPaths( string path, IType type, string[] col
136253

137254
if (path != null)
138255
{
139-
AddPropertyPath(path, type, columns, formulaTemplates);
256+
AddPropertyPath(path, type, columns, formulaTemplates, factory);
140257
}
141258

142259
if (type.IsComponentType)
@@ -165,15 +282,15 @@ protected void InitIdentifierPropertyPaths(string path, EntityType etype, string
165282
if (!hasNonIdentifierPropertyNamedId)
166283
{
167284
string idpath1 = ExtendPath(path, EntityPersister.EntityID);
168-
AddPropertyPath(idpath1, idtype, columns, null);
285+
AddPropertyPath(idpath1, idtype, columns, null, factory);
169286
InitPropertyPaths(idpath1, idtype, columns, null, factory);
170287
}
171288
}
172289

173290
if (idPropName != null)
174291
{
175292
string idpath2 = ExtendPath(path, idPropName);
176-
AddPropertyPath(idpath2, idtype, columns, null);
293+
AddPropertyPath(idpath2, idtype, columns, null, factory);
177294
InitPropertyPaths(idpath2, idtype, columns, null, factory);
178295
}
179296
}

src/NHibernate/Type/EntityType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ protected internal EntityType(string entityName, string uniqueKeyPropertyName, b
4343
this.unwrapProxy = unwrapProxy;
4444
}
4545

46+
protected EntityType(EntityType original, string superTypeEntityName)
47+
: this(superTypeEntityName, original.uniqueKeyPropertyName, original.eager, original.unwrapProxy)
48+
{
49+
50+
}
51+
4652
/// <summary> Explicitly, an entity type is an entity type </summary>
4753
/// <value> True. </value>
4854
public override sealed bool IsEntityType

src/NHibernate/Type/ManyToOneType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public ManyToOneType(string className, bool lazy)
2828
isLogicalOneToOne = false;
2929
PropertyName = null;
3030
}
31+
32+
public ManyToOneType(ManyToOneType original, string superTypeEntityName)
33+
: base(original, superTypeEntityName)
34+
{
35+
36+
}
3137

3238
//Since 5.3
3339
[Obsolete("Use Constructor with property name")]

src/NHibernate/Type/OneToOneType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public OneToOneType(string referencedEntityName, ForeignKeyDirection foreignKeyT
4040
this.propertyName = propertyName;
4141
this.entityName = entityName;
4242
}
43+
44+
public OneToOneType(OneToOneType original, string superTypeEntityName)
45+
: base(original, superTypeEntityName)
46+
{
47+
48+
}
4349

4450
public override void NullSafeSet(DbCommand st, object value, int index, bool[] settable, ISessionImplementor session)
4551
{

src/NHibernate/Type/SpecialOneToOneType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ public SpecialOneToOneType(string referencedEntityName, ForeignKeyDirection fore
1414
: base(referencedEntityName, foreignKeyType, uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName)
1515
{
1616
}
17+
18+
public SpecialOneToOneType(SpecialOneToOneType original, string superTypeEntityName)
19+
: base(original, superTypeEntityName)
20+
{
21+
22+
}
1723

1824
public override int GetColumnSpan(Engine.IMapping mapping)
1925
{

0 commit comments

Comments
 (0)