Skip to content

Commit 0def815

Browse files
committed
Fix transient detection for proxy
Fixes #2043
1 parent 22cd760 commit 0def815

File tree

8 files changed

+256
-3
lines changed

8 files changed

+256
-3
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
4+
{
5+
public class EntityWithClassLookup
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
11+
public virtual EntityWithClassProxyDefinition EntityLookup { get; set; }
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
4+
{
5+
public class EntityWithClassProxyDefinition
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
4+
{
5+
public class EntityWithInterfaceLookup
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
11+
public virtual IEntityProxy EntityLookup { get; set; }
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
4+
{
5+
public class EntityWithInterfaceProxyDefinition: IEntityProxy
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
}
11+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Linq;
3+
using NHibernate.Cfg;
4+
using NHibernate.Cfg.MappingSchema;
5+
using NHibernate.Mapping.ByCode;
6+
using NUnit.Framework;
7+
8+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
9+
{
10+
[TestFixture]
11+
public class Fixture : TestCaseMappingByCode
12+
{
13+
private Guid _entityWithClassProxy1Id;
14+
private Guid _entityWithClassProxy2Id;
15+
private Guid _entityWithInterfaceProxy1Id;
16+
private Guid _entityWithInterfaceProxy2Id;
17+
private Guid _entityWithClassLookupId;
18+
private Guid _entityWithInterfaceLookupId;
19+
20+
protected override void Configure(Configuration configuration)
21+
{
22+
base.Configure(configuration);
23+
24+
Cfg.Environment.UseReflectionOptimizer = false;
25+
}
26+
27+
28+
protected override HbmMapping GetMappings()
29+
{
30+
var mapper = new ModelMapper();
31+
mapper.Class<EntityWithClassProxyDefinition>(rc =>
32+
{
33+
rc.Proxy(typeof(EntityWithClassProxyDefinition));
34+
35+
rc.Id(x => x.Id);
36+
rc.Property(x => x.Name);
37+
});
38+
39+
mapper.Class<EntityWithInterfaceProxyDefinition>(rc =>
40+
{
41+
rc.Proxy(typeof(IEntityProxy));
42+
43+
rc.Id(x => x.Id);
44+
rc.Property(x => x.Name);
45+
});
46+
47+
mapper.Class<EntityWithClassLookup>(rc =>
48+
{
49+
rc.Id(x => x.Id);
50+
rc.Property(x => x.Name);
51+
rc.ManyToOne(x => x.EntityLookup, x => x.Class(typeof(EntityWithClassProxyDefinition)));
52+
});
53+
54+
mapper.Class<EntityWithInterfaceLookup>(rc =>
55+
{
56+
rc.Id(x => x.Id);
57+
rc.Property(x => x.Name);
58+
rc.ManyToOne(x => x.EntityLookup, x => x.Class(typeof(EntityWithInterfaceProxyDefinition)));
59+
});
60+
61+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
62+
}
63+
64+
65+
protected override void OnSetUp()
66+
{
67+
using(var session = OpenSession())
68+
{
69+
var entityCP1 = new EntityWithClassProxyDefinition
70+
{
71+
Id = Guid.NewGuid(),
72+
Name = "Name 1"
73+
};
74+
_entityWithClassProxy1Id = entityCP1.Id;
75+
76+
var entityCP2 = new EntityWithClassProxyDefinition
77+
{
78+
Id = Guid.NewGuid(),
79+
Name = "Name 2"
80+
};
81+
_entityWithClassProxy2Id = entityCP2.Id;
82+
83+
var entityIP1 = new EntityWithInterfaceProxyDefinition
84+
{
85+
Id = Guid.NewGuid(),
86+
Name = "Name 1"
87+
};
88+
_entityWithInterfaceProxy1Id = entityIP1.Id;
89+
90+
var entityIP2 = new EntityWithInterfaceProxyDefinition
91+
{
92+
Id = Guid.NewGuid(),
93+
Name = "Name 2"
94+
};
95+
_entityWithInterfaceProxy2Id = entityIP2.Id;
96+
97+
session.Save(entityCP1);
98+
session.Save(entityCP2);
99+
session.Save(entityIP1);
100+
session.Save(entityIP2);
101+
102+
var entityCL = new EntityWithClassLookup
103+
{
104+
Id = Guid.NewGuid(),
105+
Name = "Name 1",
106+
EntityLookup = (EntityWithClassProxyDefinition)session.Load(typeof(EntityWithClassProxyDefinition), entityCP1.Id)
107+
};
108+
_entityWithClassLookupId = entityCL.Id;
109+
110+
var entityIL = new EntityWithInterfaceLookup
111+
{
112+
Id = Guid.NewGuid(),
113+
Name = "Name 1",
114+
EntityLookup = (IEntityProxy)session.Load(typeof(EntityWithInterfaceProxyDefinition), entityIP1.Id)
115+
};
116+
_entityWithInterfaceLookupId = entityIL.Id;
117+
118+
session.Save(entityCL);
119+
session.Save(entityIL);
120+
121+
session.Flush();
122+
}
123+
}
124+
125+
126+
protected override void OnTearDown()
127+
{
128+
using (var session = OpenSession())
129+
{
130+
using (var transaction = session.BeginTransaction())
131+
{
132+
session.Delete("from System.Object");
133+
134+
session.Flush();
135+
transaction.Commit();
136+
}
137+
}
138+
}
139+
140+
141+
[Test]
142+
public void UpdateEntityWithClassLookup()
143+
{
144+
using (var session = OpenSession())
145+
{
146+
using(var transaction = session.BeginTransaction())
147+
{
148+
var entityToUpdate = session.Query<EntityWithClassLookup>()
149+
.First(e => e.Id == _entityWithClassLookupId);
150+
151+
entityToUpdate.EntityLookup = (EntityWithClassProxyDefinition)session.Load(typeof(EntityWithClassProxyDefinition), _entityWithClassProxy2Id);
152+
153+
session.Update(entityToUpdate);
154+
session.Flush();
155+
transaction.Rollback();
156+
}
157+
}
158+
}
159+
160+
161+
[Test]
162+
public void UpdateEntityWithInterfaceLookup()
163+
{
164+
using(var session = OpenSession())
165+
{
166+
using(var transaction = session.BeginTransaction())
167+
{
168+
var entityToUpdate = session.Query<EntityWithInterfaceLookup>()
169+
.First(e => e.Id == _entityWithInterfaceLookupId);
170+
171+
entityToUpdate.EntityLookup = (IEntityProxy)session.Load(typeof(EntityWithInterfaceProxyDefinition), _entityWithInterfaceProxy2Id);
172+
entityToUpdate.EntityLookup.Id = Guid.Empty;
173+
174+
session.Update(entityToUpdate);
175+
session.Flush();
176+
transaction.Rollback();
177+
}
178+
}
179+
}
180+
}
181+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.IlogsProxyTest
4+
{
5+
public interface IEntityProxy
6+
{
7+
Guid Id { get; set; }
8+
9+
string Name { get; set; }
10+
}
11+
}

src/NHibernate/Engine/ForeignKeys.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,17 @@ public static bool IsNotTransientSlow(string entityName, object entity, ISession
179179
}
180180

181181
// let the interceptor inspect the instance to decide
182-
// let the persister inspect the instance to decide
183-
return session.Interceptor.IsTransient(entity) ??
184-
session.GetEntityPersister(entityName, entity).IsTransient(entity, session);
182+
183+
if (session.Interceptor.IsTransient(entity) == true)
184+
return true;
185+
186+
if (entity is INHibernateProxy proxy && proxy.HibernateLazyInitializer.IsUninitialized)
187+
{
188+
return false;
189+
}
190+
191+
// let the persister inspect the instance to decide
192+
return session.GetEntityPersister(entityName, entity).IsTransient(entity, session);
185193
}
186194

187195
/// <summary>

src/NHibernate/Tuple/Entity/AbstractEntityTuplizer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public object Instantiate(object id)
114114

115115
public object GetIdentifier(object entity)
116116
{
117+
if (entity is INHibernateProxy proxy)
118+
{
119+
return proxy.HibernateLazyInitializer.Identifier;
120+
}
121+
117122
object id;
118123
if (entityMetamodel.IdentifierProperty.IsEmbedded)
119124
{

0 commit comments

Comments
 (0)