Skip to content

Commit

Permalink
Fix NullReferenceException in EntityEntry.GetLoadedValue
Browse files Browse the repository at this point in the history
Fixes nhibernate#2137

Co-authored-by: Roman Artiukhin <[email protected]>
  • Loading branch information
2 people authored and hazzik committed May 14, 2019
1 parent a05b336 commit b734d00
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 2 deletions.
61 changes: 61 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH2137/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2137
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : BugTestCase
{
private Entity e1;

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
e1 = new Entity {Name = "Bob"};
session.Save(e1);

transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
// The HQL delete does all the job inside the database without loading the entities, but it does
// not handle delete order for avoiding violating constraints if any. Use
// session.Delete("from System.Object");
// instead if in need of having NHibernate ordering the deletes, but this will cause
// loading the entities in the session.
session.CreateQuery("delete from System.Object").ExecuteUpdate();

transaction.Commit();
}
}

[Test]
public async Task TestUpdateDetachedEntityAsync()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
e1.Name = "Sally";
await (session.UpdateAsync(e1));
await (transaction.CommitAsync());
}
}
}
}
18 changes: 18 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2137/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace NHibernate.Test.NHSpecificTest.GH2137
{
class Entity
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ExtendedProperties ExtendedProperties { get; set; }
}

class ExtendedProperties
{
public virtual Guid Id { get; set; }

public virtual string Value { get; set; }
}
}
50 changes: 50 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2137/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2137
{
[TestFixture]
public class Fixture : BugTestCase
{
private Entity e1;

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
e1 = new Entity {Name = "Bob"};
session.Save(e1);

transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
// The HQL delete does all the job inside the database without loading the entities, but it does
// not handle delete order for avoiding violating constraints if any. Use
// session.Delete("from System.Object");
// instead if in need of having NHibernate ordering the deletes, but this will cause
// loading the entities in the session.
session.CreateQuery("delete from System.Object").ExecuteUpdate();

transaction.Commit();
}
}

[Test]
public void TestUpdateDetachedEntity()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
e1.Name = "Sally";
session.Update(e1);
transaction.Commit();
}
}
}
}
17 changes: 17 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2137/Mappings.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
namespace="NHibernate.Test.NHSpecificTest.GH2137">

<class name="Entity">
<id name="Id" generator="guid.comb"/>
<property name="Name"/>
<many-to-one name="ExtendedProperties" class="ExtendedProperties" unique="true" cascade="all-delete-orphan" lazy="proxy" />

</class>

<class name="ExtendedProperties">
<id name="Id" generator="guid.comb"/>
<property name="Value" column="`Value`"/>
</class>

</hibernate-mapping>
3 changes: 2 additions & 1 deletion src/NHibernate/Async/Engine/Cascade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ private async Task CascadePropertyAsync(object parent, object child, IType type,
// value is orphaned if loaded state for this property shows not null
// because it is currently null.
EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent);
if (entry != null && entry.Status != Status.Saving)
//LoadedState is null when detached entity is cascaded from session.Update context
if (entry?.LoadedState != null && entry.Status != Status.Saving)
{
object loadedValue;
if (componentPathStack.Count == 0)
Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate/Engine/Cascade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ private void CascadeProperty(object parent, object child, IType type, CascadeSty
// value is orphaned if loaded state for this property shows not null
// because it is currently null.
EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent);
if (entry != null && entry.Status != Status.Saving)
//LoadedState is null when detached entity is cascaded from session.Update context
if (entry?.LoadedState != null && entry.Status != Status.Saving)
{
object loadedValue;
if (componentPathStack.Count == 0)
Expand Down

0 comments on commit b734d00

Please sign in to comment.