Skip to content

Commit 95d78af

Browse files
bahusoidhazzik
authored andcommitted
Fix property-ref ignoring not-found="exception" mapping
1 parent 5ee4401 commit 95d78af

File tree

9 files changed

+118
-4
lines changed

9 files changed

+118
-4
lines changed

src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,20 @@ public async Task Department5IsNullAsync()
255255
}
256256
}
257257

258+
[Test]
259+
public void Department5IsNotFoundAsync()
260+
{
261+
var statistics = Sfi.Statistics;
262+
statistics.Clear();
263+
264+
using (var session = OpenSession())
265+
using(var transaction = session.BeginTransaction())
266+
{
267+
ExecuteStatement(session, transaction, $"UPDATE EMPLOYEES SET DEPARTMENT_ID_1 = 11, DEPARTMENT_ID_2 = 12, DEPARTMENT_ID_3 = 13, DEPARTMENT_ID_4 = 24, DEPARTMENT_ID_5 = 99999, ADDRESS_ID = 31 WHERE EMPLOYEE_ID = {employeeId}");
268+
Assert.That(() => session.GetAsync<Employee>(employeeId), Throws.InstanceOf<ObjectNotFoundByUniqueKeyException>());
269+
}
270+
}
271+
258272
[Test]
259273
public async Task AddressNullAsync()
260274
{

src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public void Department5IsNull()
244244
}
245245
}
246246

247-
[Test, Ignore("Not fixed yet")]
247+
[Test]
248248
public void Department5IsNotFound()
249249
{
250250
var statistics = Sfi.Statistics;
@@ -254,7 +254,7 @@ public void Department5IsNotFound()
254254
using(var transaction = session.BeginTransaction())
255255
{
256256
ExecuteStatement(session, transaction, $"UPDATE EMPLOYEES SET DEPARTMENT_ID_1 = 11, DEPARTMENT_ID_2 = 12, DEPARTMENT_ID_3 = 13, DEPARTMENT_ID_4 = 24, DEPARTMENT_ID_5 = 99999, ADDRESS_ID = 31 WHERE EMPLOYEE_ID = {employeeId}");
257-
Assert.That(() => session.Get<Employee>(employeeId), Throws.InstanceOf<ObjectNotFoundException>());
257+
Assert.That(() => session.Get<Employee>(employeeId), Throws.InstanceOf<ObjectNotFoundByUniqueKeyException>());
258258
}
259259
}
260260

src/NHibernate/Async/Type/EntityType.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ public async Task<object> LoadByUniqueKeyAsync(string entityName, string uniqueK
235235
if (result == null)
236236
{
237237
result = await (persister.LoadByUniqueKeyAsync(uniqueKeyPropertyName, key, session, cancellationToken)).ConfigureAwait(false);
238+
if (result == null && !IsNullable)
239+
{
240+
factory.EntityNotFoundDelegate.HandleEntityNotFound(entityName, uniqueKeyPropertyName, key);
241+
}
238242
}
239243
return result == null ? null : persistenceContext.ProxyFor(result);
240244
}

src/NHibernate/Impl/SessionFactoryImpl.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public sealed partial class SessionFactoryImpl : ISessionFactoryImplementor, IOb
7777
{
7878
#region Default entity not found delegate
7979

80-
private class DefaultEntityNotFoundDelegate : IEntityNotFoundDelegate
80+
internal class DefaultEntityNotFoundDelegate : IEntityNotFoundDelegate
8181
{
8282
#region IEntityNotFoundDelegate Members
8383

@@ -86,6 +86,11 @@ public void HandleEntityNotFound(string entityName, object id)
8686
throw new ObjectNotFoundException(id, entityName);
8787
}
8888

89+
public void HandleEntityNotFound(string entityName, string propertyName, object key)
90+
{
91+
throw new ObjectNotFoundByUniqueKeyException(entityName, propertyName, key);
92+
}
93+
8994
#endregion
9095
}
9196

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Runtime.Serialization;
3+
using System.Security;
4+
using NHibernate.Impl;
5+
6+
namespace NHibernate
7+
{
8+
/// <summary>
9+
/// Thrown when entity can't be found by given unique key
10+
/// </summary>
11+
[Serializable]
12+
public class ObjectNotFoundByUniqueKeyException : HibernateException
13+
{
14+
/// <summary>
15+
/// Property name
16+
/// </summary>
17+
public string PropertyName { get; }
18+
19+
/// <summary>
20+
/// Key
21+
/// </summary>
22+
public object Key { get; }
23+
24+
/// <summary>
25+
/// Thrown when entity can't be found by given unique key
26+
/// </summary>
27+
/// <param name="entityName">Entity name</param>
28+
/// <param name="propertyName">Property name</param>
29+
/// <param name="key">Key</param>
30+
public ObjectNotFoundByUniqueKeyException(string entityName, string propertyName, object key)
31+
: base("No row with given unique key found " + MessageHelper.InfoString(entityName, propertyName, key))
32+
{
33+
Key = key;
34+
PropertyName = propertyName;
35+
}
36+
37+
#region Serialization
38+
39+
protected ObjectNotFoundByUniqueKeyException(SerializationInfo info, StreamingContext context)
40+
: base(info, context)
41+
{
42+
Key = info.GetValue(nameof(Key), typeof(object));
43+
PropertyName = info.GetString(nameof(PropertyName));
44+
}
45+
46+
[SecurityCritical]
47+
public override void GetObjectData(SerializationInfo info, StreamingContext context)
48+
{
49+
base.GetObjectData(info, context);
50+
info.AddValue(nameof(Key), Key);
51+
info.AddValue(nameof(PropertyName), PropertyName);
52+
}
53+
54+
#endregion Serialization
55+
}
56+
}

src/NHibernate/Proxy/IEntityNotFoundDelegate.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
namespace NHibernate.Proxy
22
{
3+
//6.0 TODO Add to IEntityNotFoundDelegate interface
4+
internal static class EntityNotFoundDelegateExtension
5+
{
6+
/// <summary>
7+
/// Method to handle the scenario of an entity not found by unique key.
8+
/// </summary>
9+
/// <param name="interceptor"></param>
10+
/// <param name="entityName">The entityName (may be the class fullname)</param>
11+
/// <param name="propertyName">Property name</param>
12+
/// <param name="key">Key</param>
13+
public static void HandleEntityNotFound(
14+
this IEntityNotFoundDelegate interceptor,
15+
string entityName,
16+
string propertyName,
17+
object key)
18+
{
19+
if (interceptor is Impl.SessionFactoryImpl.DefaultEntityNotFoundDelegate x)
20+
{
21+
x.HandleEntityNotFound(entityName, propertyName, key);
22+
return;
23+
}
24+
25+
new Impl.SessionFactoryImpl.DefaultEntityNotFoundDelegate().HandleEntityNotFound(entityName, propertyName, key);
26+
}
27+
}
28+
329
/// <summary>
430
/// Delegate to handle the scenario of an entity not found by a specified id.
531
/// </summary>

src/NHibernate/Type/EntityType.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ public bool IsUniqueKeyReference
291291
get { return uniqueKeyPropertyName != null; }
292292
}
293293

294+
/// <summary>
295+
/// True if not null entity key can represent null entity
296+
/// (e.g. entity mapped with not-found="ignore" or not constrained one-to-one mapping)
297+
/// </summary>
294298
public abstract bool IsNullable { get; }
295299

296300
/// <summary> Retrieves the {@link Joinable} defining the associated entity. </summary>
@@ -530,6 +534,10 @@ public object LoadByUniqueKey(string entityName, string uniqueKeyPropertyName, o
530534
if (result == null)
531535
{
532536
result = persister.LoadByUniqueKey(uniqueKeyPropertyName, key, session);
537+
if (result == null && !IsNullable)
538+
{
539+
factory.EntityNotFoundDelegate.HandleEntityNotFound(entityName, uniqueKeyPropertyName, key);
540+
}
533541
}
534542
return result == null ? null : persistenceContext.ProxyFor(result);
535543
}

src/NHibernate/Type/ManyToOneType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ public override bool IsDirty(object old, object current, bool[] checkable, ISess
236236
return IsDirtyManyToOne(old, current, IsAlwaysDirtyChecked ? null : checkable, session);
237237
}
238238

239-
239+
/// <inheritdoc />
240240
public override bool IsNullable
241241
{
242242
get { return ignoreNotFound; }

src/NHibernate/Type/OneToOneType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ public override object Hydrate(DbDataReader rs, string[] names, ISessionImplemen
122122
return identifier;
123123
}
124124

125+
/// <inheritdoc />
125126
public override bool IsNullable
126127
{
127128
get { return foreignKeyDirection.Equals(ForeignKeyDirection.ForeignKeyToParent); }

0 commit comments

Comments
 (0)