Skip to content

Commit 0c96305

Browse files
committed
Fix cloning entities with non public parameterless constructor
1 parent 54d5f78 commit 0c96305

File tree

4 files changed

+30
-30
lines changed

4 files changed

+30
-30
lines changed

Source/NHibernate.Extensions.Tests/BaseIncludeTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ public void Cleanup()
5656
protected void FillData()
5757
{
5858
var system = new EQBUser { UserName = "System" };
59-
var ana = new EQBPerson { Age = 23, Name = "Ana", CreatedBy = system };
60-
var rok = new EQBPerson { Age = 24, Name = "Rok", CreatedBy = system };
61-
var simon = new EQBPerson { Age = 25, Name = "Simon", CreatedBy = system };
62-
var petra = new EQBPerson { Age = 22, Name = "Petra", CreatedBy = system };
59+
var ana = new EQBPerson("Ana") { Age = 23, CreatedBy = system };
60+
var rok = new EQBPerson("Rok") { Age = 24, CreatedBy = system };
61+
var simon = new EQBPerson("Simon") { Age = 25, CreatedBy = system };
62+
var petra = new EQBPerson("Petra") { Age = 22, CreatedBy = system };
6363

6464
//Setting best friends
6565
petra.BestFriend = ana;

Source/NHibernate.Extensions.Tests/Entities/EQBPerson.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ public interface IPerson
1515

1616
public partial class EQBPerson : Entity, IPerson
1717
{
18-
public EQBPerson()
18+
public EQBPerson(string name) : this()
19+
{
20+
Name = name;
21+
}
22+
23+
protected EQBPerson()
1924
{
2025
CurrentOwnedVehicles = new HashSet<EQBVehicle>();
2126
OwnedHouses = new HashSet<EQBHouse>();

Source/NHibernate.Extensions/DeepClone/DeepCloneSessionExtension.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using NHibernate.Persister.Entity;
1111
using NHibernate.Proxy;
1212
using NHibernate.Type;
13+
using NHibernate.Util;
1314

1415
namespace NHibernate.Extensions
1516
{
@@ -201,9 +202,9 @@ private static object DeepClone(this ISessionImplementor session, object entity,
201202
IDictionary<object, object> resolvedEntities, DeepCloneParentEntity parentEntity = null)
202203
{
203204
opts = opts ?? new DeepCloneOptions();
204-
if (entity == null)
205+
if (entity == null || !NHibernateUtil.IsInitialized(entity))
205206
return entityType.GetDefaultValue();
206-
entityType = entityType ?? entity.GetUnproxiedType();
207+
entityType = entityType ?? entity.GetUnproxiedType(true);
207208

208209
if (entityType.IsSimpleType())
209210
return entity;
@@ -218,9 +219,6 @@ private static object DeepClone(this ISessionImplementor session, object entity,
218219
return entityType.GetDefaultValue();
219220
}
220221

221-
if (!NHibernateUtil.IsInitialized(entity))
222-
return entityType.GetDefaultValue();
223-
224222
if (resolvedEntities.ContainsKey(entity) && parentEntity != null)
225223
return CopyOnlyForeignKeyProperties(resolvedEntities[entity], entityType, entityMetadata, opts, parentEntity);
226224

@@ -231,7 +229,7 @@ private static object DeepClone(this ISessionImplementor session, object entity,
231229
return entity;
232230

233231
var propertyInfos = entityType.GetProperties();
234-
var copiedEntity = Activator.CreateInstance(entityType);
232+
var copiedEntity = ReflectHelper.GetDefaultConstructor(entityType).Invoke(new object[0]);
235233
resolvedEntities.Add(entity, copiedEntity);
236234

237235
foreach (var propertyInfo in propertyInfos
@@ -293,7 +291,7 @@ private static object DeepClone(this ISessionImplementor session, object entity,
293291
propertyInfo.SetValue(copiedEntity, propertyList, null);
294292
AddItemToCollection(propertyList, propertyValue, o => copyAsReference
295293
? o
296-
: session.DeepClone(o, opts, o.GetUnproxiedType(), resolvedEntities,
294+
: session.DeepClone(o, opts, null, resolvedEntities,
297295
new DeepCloneParentEntity
298296
{
299297
Entity = copiedEntity,

Source/NHibernate.Extensions/Internal/TypeHelper.cs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,26 @@ public static bool IsSubclassOfRawGeneric(System.Type generic, System.Type toChe
2323
/// <summary>
2424
/// Gets the underlying class type of a persistent object that may be proxied
2525
/// </summary>
26-
public static System.Type GetUnproxiedType(this object persistentObject)
26+
public static System.Type GetUnproxiedType(this object entity, bool allowInitialization)
2727
{
28-
var proxy = persistentObject as INHibernateProxy;
29-
if (proxy != null)
30-
return proxy.HibernateLazyInitializer.PersistentClass;
31-
32-
var nhProxy = persistentObject as IProxy;
33-
if (nhProxy == null)
34-
return persistentObject.GetType();
28+
if (entity is INHibernateProxy nhProxy)
29+
{
30+
if (nhProxy.HibernateLazyInitializer.IsUninitialized && !allowInitialization)
31+
{
32+
return nhProxy.HibernateLazyInitializer.PersistentClass;
33+
}
3534

36-
var lazyInitializer = nhProxy.Interceptor as ILazyInitializer;
37-
if (lazyInitializer != null)
38-
return lazyInitializer.PersistentClass;
35+
// We have to initialize in case of a subclass to get the concrete type
36+
entity = nhProxy.HibernateLazyInitializer.GetImplementation();
37+
}
3938

40-
var fieldInterceptorAccessor = nhProxy.Interceptor as IFieldInterceptorAccessor;
41-
if (fieldInterceptorAccessor != null)
39+
switch (entity)
4240
{
43-
return fieldInterceptorAccessor.FieldInterceptor == null
44-
? nhProxy.GetType().BaseType
45-
: fieldInterceptorAccessor.FieldInterceptor.MappedClass;
41+
case IFieldInterceptorAccessor interceptorAccessor:
42+
return interceptorAccessor.FieldInterceptor.MappedClass;
43+
default:
44+
return entity.GetType();
4645
}
47-
48-
return persistentObject.GetType();
4946
}
5047
}
5148
}

0 commit comments

Comments
 (0)