From 3bb99e9feba1af9b9bb7618b0065d472be61941a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?=
<12201973+fredericdelaporte@users.noreply.github.com>
Date: Sun, 27 Dec 2020 19:18:53 +0100
Subject: [PATCH 1/3] Add test for #2627
---
.../Async/NHSpecificTest/GH2627/Fixture.cs | 69 +++++++++++++++++++
.../NHSpecificTest/GH2627/Child.cs | 11 +++
.../NHSpecificTest/GH2627/Entity.cs | 10 +++
.../NHSpecificTest/GH2627/Fixture.cs | 57 +++++++++++++++
.../NHSpecificTest/GH2627/Mappings.hbm.xml | 16 +++++
5 files changed, 163 insertions(+)
create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH2627/Fixture.cs
create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2627/Child.cs
create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2627/Entity.cs
create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2627/Fixture.cs
create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2627/Mappings.hbm.xml
diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2627/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2627/Fixture.cs
new file mode 100644
index 00000000000..ac24f9f72c5
--- /dev/null
+++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2627/Fixture.cs
@@ -0,0 +1,69 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by AsyncGenerator.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+
+using System.Linq;
+using NUnit.Framework;
+using NHibernate.Linq;
+
+namespace NHibernate.Test.NHSpecificTest.GH2627
+{
+ using System.Threading.Tasks;
+ [TestFixture]
+ public class FixtureAsync : BugTestCase
+ {
+ protected override void OnSetUp()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ var e1 = new Entity {Name = "Bob"};
+ session.Save(e1);
+
+ transaction.Commit();
+ }
+ }
+
+ protected override void OnTearDown()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ session.CreateQuery("delete from Child").ExecuteUpdate();
+ session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+ transaction.Commit();
+ }
+ }
+
+ [Test]
+ public async Task NullRefInMergeAsync()
+ {
+ Child child;
+ using (var session = OpenSession())
+ using (var t = session.BeginTransaction())
+ {
+ child = new Child
+ {
+ Parent = await (session.Query().FirstOrDefaultAsync()),
+ Name = "John"
+ };
+
+ await (t.CommitAsync());
+ }
+
+ using (var session = OpenSession())
+ using (var t = session.BeginTransaction())
+ {
+ await (session.MergeAsync(child));
+ await (t.CommitAsync());
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH2627/Child.cs b/src/NHibernate.Test/NHSpecificTest/GH2627/Child.cs
new file mode 100644
index 00000000000..55ac0288207
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH2627/Child.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.GH2627
+{
+ public class Child
+ {
+ public virtual Guid Id { get; set; }
+ public virtual Entity Parent { get; set; }
+ public virtual string Name { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH2627/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH2627/Entity.cs
new file mode 100644
index 00000000000..8757939fdf4
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH2627/Entity.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.GH2627
+{
+ public class Entity
+ {
+ public virtual Guid Id { get; set; }
+ public virtual string Name { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH2627/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2627/Fixture.cs
new file mode 100644
index 00000000000..44f36d3a503
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH2627/Fixture.cs
@@ -0,0 +1,57 @@
+using System.Linq;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.GH2627
+{
+ [TestFixture]
+ public class Fixture : BugTestCase
+ {
+ protected override void OnSetUp()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ var e1 = new Entity {Name = "Bob"};
+ session.Save(e1);
+
+ transaction.Commit();
+ }
+ }
+
+ protected override void OnTearDown()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ session.CreateQuery("delete from Child").ExecuteUpdate();
+ session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+ transaction.Commit();
+ }
+ }
+
+ [Test]
+ public void NullRefInMerge()
+ {
+ Child child;
+ using (var session = OpenSession())
+ using (var t = session.BeginTransaction())
+ {
+ child = new Child
+ {
+ Parent = session.Query().FirstOrDefault(),
+ Name = "John"
+ };
+
+ t.Commit();
+ }
+
+ using (var session = OpenSession())
+ using (var t = session.BeginTransaction())
+ {
+ session.Merge(child);
+ t.Commit();
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH2627/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH2627/Mappings.hbm.xml
new file mode 100644
index 00000000000..6c4296a93e9
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH2627/Mappings.hbm.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 972b856861051f67255a352e1a5b24accde0fdfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?=
<12201973+fredericdelaporte@users.noreply.github.com>
Date: Sun, 31 Jan 2021 21:56:20 +0100
Subject: [PATCH 2/3] Fix #2627
---
src/NHibernate/Async/Type/ManyToOneType.cs | 1 -
.../XmlHbmBinding/ClassCompositeIdBinder.cs | 2 +-
.../Cfg/XmlHbmBinding/CollectionBinder.cs | 6 +--
.../Cfg/XmlHbmBinding/PropertiesBinder.cs | 4 +-
src/NHibernate/Mapping/ManyToOne.cs | 22 ++++++++--
src/NHibernate/Mapping/OneToMany.cs | 4 +-
src/NHibernate/Type/ManyToOneType.cs | 42 +++++++++++++++----
src/NHibernate/Type/TypeFactory.cs | 27 ++++++++++--
8 files changed, 86 insertions(+), 22 deletions(-)
diff --git a/src/NHibernate/Async/Type/ManyToOneType.cs b/src/NHibernate/Async/Type/ManyToOneType.cs
index e288555bddb..d341713e944 100644
--- a/src/NHibernate/Async/Type/ManyToOneType.cs
+++ b/src/NHibernate/Async/Type/ManyToOneType.cs
@@ -11,7 +11,6 @@
using System;
using System.Data.Common;
using NHibernate.Engine;
-using NHibernate.Persister.Entity;
using NHibernate.SqlTypes;
using NHibernate.Util;
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
index 00e384c5e76..cd22cf6d6fb 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
@@ -101,7 +101,7 @@ private void BindComponent(System.Type reflectedClass, string path, HbmComposite
if (keyManyToOneSchema != null)
{
- var manyToOne = new ManyToOne(compositeId.Table);
+ var manyToOne = new ManyToOne(compositeId.Table, compositeId.Owner);
string propertyName = keyManyToOneSchema.name == null ? null : StringHelper.Qualify(path, keyManyToOneSchema.name);
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
index 8984459d119..d82bca86d76 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
@@ -655,13 +655,13 @@ private void BindMapSecondPass(HbmMap mapMapping, Map model,
}
else if ((indexManyToManyMapping = mapMapping.Item as HbmIndexManyToMany) != null)
{
- var manyToOne = new ManyToOne(model.CollectionTable);
+ var manyToOne = new ManyToOne(model.CollectionTable, model.Owner);
BindIndexManyToMany(indexManyToManyMapping, manyToOne, IndexedCollection.DefaultIndexColumnName, model.IsOneToMany);
model.Index = manyToOne;
}
else if ((mapKeyManyToManyMapping = mapMapping.Item as HbmMapKeyManyToMany) != null)
{
- var manyToOne = new ManyToOne(model.CollectionTable);
+ var manyToOne = new ManyToOne(model.CollectionTable, model.Owner);
BindMapKeyManyToMany(mapKeyManyToManyMapping, manyToOne, IndexedCollection.DefaultIndexColumnName, model.IsOneToMany);
model.Index = manyToOne;
}
@@ -813,7 +813,7 @@ private void BindCollectionSecondPass(ICollectionPropertiesMapping collectionMap
private void BindManyToMany(HbmManyToMany manyToManyMapping, Mapping.Collection model)
{
- var manyToMany = new ManyToOne(model.CollectionTable);
+ var manyToMany = new ManyToOne(model.CollectionTable, model.Owner);
model.Element = manyToMany;
new ValuePropertyBinder(manyToMany, Mappings).BindSimpleValue(manyToManyMapping,
Mapping.Collection.DefaultElementColumnName, false);
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
index 3fbbc63aa57..706cb9e81c1 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
@@ -129,7 +129,7 @@ public void Bind(IEnumerable properties, Table table, ID
}
else if ((manyToOneMapping = entityPropertyMapping as HbmManyToOne) != null)
{
- var value = new ManyToOne(table);
+ var value = new ManyToOne(table, persistentClass);
BindManyToOne(manyToOneMapping, value, propertyName, true);
property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas);
BindManyToOneProperty(manyToOneMapping, property);
@@ -189,7 +189,7 @@ public void Bind(IEnumerable properties, Table table, ID
}
else if ((keyManyToOneMapping = entityPropertyMapping as HbmKeyManyToOne) != null)
{
- var value = new ManyToOne(table);
+ var value = new ManyToOne(table, persistentClass);
BindKeyManyToOne(keyManyToOneMapping, value, propertyName, componetDefaultNullable);
property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas);
}
diff --git a/src/NHibernate/Mapping/ManyToOne.cs b/src/NHibernate/Mapping/ManyToOne.cs
index 7500f7f7997..711c14247ca 100644
--- a/src/NHibernate/Mapping/ManyToOne.cs
+++ b/src/NHibernate/Mapping/ManyToOne.cs
@@ -9,11 +9,24 @@ namespace NHibernate.Mapping
[Serializable]
public class ManyToOne : ToOne
{
+ private readonly string _entityName;
+
+ ///
+ /// Construct a many-to-one mapping.
+ ///
+ /// The table.
+ /// The association owner.
+ public ManyToOne(Table table, PersistentClass owner) : base(table)
+ {
+ _entityName = owner?.EntityName;
+ }
+
///
///
///
///
- public ManyToOne(Table table) : base(table)
+ [Obsolete("Use overload with owner instead.")]
+ public ManyToOne(Table table) : this(table, null)
{
}
@@ -41,7 +54,7 @@ public bool IsLogicalOneToOne
get { return isLogicalOneToOne; }
set { isLogicalOneToOne = value; }
}
-
+
public string PropertyName { get; set; }
private IType type;
@@ -51,8 +64,9 @@ public override IType Type
{
if (type == null)
{
- type =
- TypeFactory.ManyToOne(ReferencedEntityName, ReferencedPropertyName, IsLazy, UnwrapProxy, IsIgnoreNotFound, isLogicalOneToOne, PropertyName);
+ type = TypeFactory.ManyToOne(
+ ReferencedEntityName, ReferencedPropertyName, IsLazy, UnwrapProxy,
+ IsIgnoreNotFound, isLogicalOneToOne, _entityName, PropertyName);
}
return type;
}
diff --git a/src/NHibernate/Mapping/OneToMany.cs b/src/NHibernate/Mapping/OneToMany.cs
index b349e4df98b..0d92d564d66 100644
--- a/src/NHibernate/Mapping/OneToMany.cs
+++ b/src/NHibernate/Mapping/OneToMany.cs
@@ -23,7 +23,9 @@ public OneToMany(PersistentClass owner)
private EntityType EntityType
{
- get { return TypeFactory.ManyToOne(ReferencedEntityName, null, false, false, IsIgnoreNotFound, false, null); }
+ get { return TypeFactory.ManyToOne(
+ ReferencedEntityName, null, false, false,
+ IsIgnoreNotFound, false, null, null); }
}
public bool IsIgnoreNotFound
diff --git a/src/NHibernate/Type/ManyToOneType.cs b/src/NHibernate/Type/ManyToOneType.cs
index b38fb35eba8..00b54cdaf0c 100644
--- a/src/NHibernate/Type/ManyToOneType.cs
+++ b/src/NHibernate/Type/ManyToOneType.cs
@@ -1,7 +1,6 @@
using System;
using System.Data.Common;
using NHibernate.Engine;
-using NHibernate.Persister.Entity;
using NHibernate.SqlTypes;
using NHibernate.Util;
@@ -15,6 +14,7 @@ public partial class ManyToOneType : EntityType
{
private readonly bool ignoreNotFound;
private readonly bool isLogicalOneToOne;
+ private readonly string _entityName;
public ManyToOneType(string className)
: this(className, false)
@@ -30,18 +30,41 @@ public ManyToOneType(string className, bool lazy)
}
//Since 5.3
- [Obsolete("Use Constructor with property name")]
+ [Obsolete("Use Constructor with owner property name and property name")]
public ManyToOneType(string entityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne)
- : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null)
+ : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, null)
{
}
+ //Since 5.3.6
+ [Obsolete("Use Constructor with owner entity name")]
public ManyToOneType(string entityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne, string propertyName)
- : base(entityName, uniqueKeyPropertyName, !lazy, unwrapProxy)
+ : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, propertyName)
+ {
+ }
+
+ ///
+ /// Build a many-to-one relation.
+ ///
+ /// The referenced entity name.
+ /// The property-ref name, or if we reference
+ /// the PK of the associated entity.
+ /// Is the association lazily loaded?
+ /// Is unwrapping of proxies allowed for this association; unwrapping says to return
+ /// the "implementation target" of lazy proxies; typically only possible with lazy="no-proxy".
+ /// for throwing an exception if the referenced
+ /// entity is missing in the database, for yielding instead.
+ ///
+ /// The property owner entity name.
+ /// The property name.
+ public ManyToOneType(string referencedEntityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy,
+ bool ignoreNotFound, bool isLogicalOneToOne, string entityName, string propertyName)
+ : base(referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy)
{
this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne;
PropertyName = propertyName;
+ _entityName = entityName;
}
public override int GetColumnSpan(IMapping mapping)
@@ -162,11 +185,16 @@ private bool IsIdentifier(object value, ISessionImplementor session)
public override bool IsNull(object owner, ISessionImplementor session)
{
- if (IsNullable && !string.IsNullOrEmpty(PropertyName))
+ if (IsNullable && !string.IsNullOrEmpty(PropertyName) && owner != null)
{
- EntityEntry entry = session.PersistenceContext.GetEntry(owner);
+ var ownerPersister = session.Factory.GetEntityPersister(_entityName);
+ var id = session.GetContextEntityIdentifier(owner);
+ if (id == null)
+ return false;
+
+ var entityKey = session.GenerateEntityKey(id, ownerPersister);
- return session.PersistenceContext.IsPropertyNull(entry.EntityKey, PropertyName);
+ return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
}
return false;
diff --git a/src/NHibernate/Type/TypeFactory.cs b/src/NHibernate/Type/TypeFactory.cs
index 271b85ff4ea..eb33be5997a 100644
--- a/src/NHibernate/Type/TypeFactory.cs
+++ b/src/NHibernate/Type/TypeFactory.cs
@@ -957,18 +957,39 @@ public static EntityType ManyToOne(string persistentClass, bool lazy)
///
/// A many-to-one association type for the given class and cascade style.
///
+ /// The referenced class.
+ /// The property-ref name, or if we reference
+ /// the PK of the associated entity.
+ /// Is the association lazily loaded?
+ /// Is unwrapping of proxies allowed for this association; unwrapping says to return
+ /// the "implementation target" of lazy proxies; typically only possible with lazy="no-proxy".
+ /// for throwing an exception if the referenced
+ /// entity is missing in the database, for yielding instead.
+ ///
+ /// The property owner entity name.
+ /// The property name.
+ public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy,
+ bool ignoreNotFound, bool isLogicalOneToOne, string entityName, string propertyName)
+ {
+ return new ManyToOneType(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, entityName, propertyName);
+ }
+
+ ///
+ /// A many-to-one association type for the given class and cascade style.
+ ///
+ [Obsolete("Use ManyToOne with owner entity name")]
public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne, string propertyName)
{
- return new ManyToOneType(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, propertyName);
+ return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, propertyName);
}
///
/// A many-to-one association type for the given class and cascade style.
///
- [Obsolete("Use ManyToOne with propertyName")]
+ [Obsolete("Use ManyToOne with owner entity name and propertyName")]
public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne)
{
- return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null);
+ return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, null);
}
public static CollectionType Array(string role, string propertyRef, System.Type elementClass)
From 2f6c555e5e511310759f14ff93e408ca9c93f222 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?=
<12201973+fredericdelaporte@users.noreply.github.com>
Date: Sat, 6 Feb 2021 18:52:34 +0100
Subject: [PATCH 3/3] Revert and do a simpler fix
Co-authored-by: Roman Artiukhin
---
src/NHibernate/Async/Type/ManyToOneType.cs | 1 +
.../XmlHbmBinding/ClassCompositeIdBinder.cs | 2 +-
.../Cfg/XmlHbmBinding/CollectionBinder.cs | 6 +-
.../Cfg/XmlHbmBinding/PropertiesBinder.cs | 4 +-
src/NHibernate/Mapping/ManyToOne.cs | 22 ++------
src/NHibernate/Mapping/OneToMany.cs | 4 +-
src/NHibernate/Type/ManyToOneType.cs | 56 +++++++------------
src/NHibernate/Type/TypeFactory.cs | 27 +--------
8 files changed, 34 insertions(+), 88 deletions(-)
diff --git a/src/NHibernate/Async/Type/ManyToOneType.cs b/src/NHibernate/Async/Type/ManyToOneType.cs
index d341713e944..d5615a85d7a 100644
--- a/src/NHibernate/Async/Type/ManyToOneType.cs
+++ b/src/NHibernate/Async/Type/ManyToOneType.cs
@@ -11,6 +11,7 @@
using System;
using System.Data.Common;
using NHibernate.Engine;
+using NHibernate.Proxy;
using NHibernate.SqlTypes;
using NHibernate.Util;
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
index cd22cf6d6fb..00e384c5e76 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/ClassCompositeIdBinder.cs
@@ -101,7 +101,7 @@ private void BindComponent(System.Type reflectedClass, string path, HbmComposite
if (keyManyToOneSchema != null)
{
- var manyToOne = new ManyToOne(compositeId.Table, compositeId.Owner);
+ var manyToOne = new ManyToOne(compositeId.Table);
string propertyName = keyManyToOneSchema.name == null ? null : StringHelper.Qualify(path, keyManyToOneSchema.name);
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
index d82bca86d76..8984459d119 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/CollectionBinder.cs
@@ -655,13 +655,13 @@ private void BindMapSecondPass(HbmMap mapMapping, Map model,
}
else if ((indexManyToManyMapping = mapMapping.Item as HbmIndexManyToMany) != null)
{
- var manyToOne = new ManyToOne(model.CollectionTable, model.Owner);
+ var manyToOne = new ManyToOne(model.CollectionTable);
BindIndexManyToMany(indexManyToManyMapping, manyToOne, IndexedCollection.DefaultIndexColumnName, model.IsOneToMany);
model.Index = manyToOne;
}
else if ((mapKeyManyToManyMapping = mapMapping.Item as HbmMapKeyManyToMany) != null)
{
- var manyToOne = new ManyToOne(model.CollectionTable, model.Owner);
+ var manyToOne = new ManyToOne(model.CollectionTable);
BindMapKeyManyToMany(mapKeyManyToManyMapping, manyToOne, IndexedCollection.DefaultIndexColumnName, model.IsOneToMany);
model.Index = manyToOne;
}
@@ -813,7 +813,7 @@ private void BindCollectionSecondPass(ICollectionPropertiesMapping collectionMap
private void BindManyToMany(HbmManyToMany manyToManyMapping, Mapping.Collection model)
{
- var manyToMany = new ManyToOne(model.CollectionTable, model.Owner);
+ var manyToMany = new ManyToOne(model.CollectionTable);
model.Element = manyToMany;
new ValuePropertyBinder(manyToMany, Mappings).BindSimpleValue(manyToManyMapping,
Mapping.Collection.DefaultElementColumnName, false);
diff --git a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
index 706cb9e81c1..3fbbc63aa57 100644
--- a/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
+++ b/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs
@@ -129,7 +129,7 @@ public void Bind(IEnumerable properties, Table table, ID
}
else if ((manyToOneMapping = entityPropertyMapping as HbmManyToOne) != null)
{
- var value = new ManyToOne(table, persistentClass);
+ var value = new ManyToOne(table);
BindManyToOne(manyToOneMapping, value, propertyName, true);
property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas);
BindManyToOneProperty(manyToOneMapping, property);
@@ -189,7 +189,7 @@ public void Bind(IEnumerable properties, Table table, ID
}
else if ((keyManyToOneMapping = entityPropertyMapping as HbmKeyManyToOne) != null)
{
- var value = new ManyToOne(table, persistentClass);
+ var value = new ManyToOne(table);
BindKeyManyToOne(keyManyToOneMapping, value, propertyName, componetDefaultNullable);
property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas);
}
diff --git a/src/NHibernate/Mapping/ManyToOne.cs b/src/NHibernate/Mapping/ManyToOne.cs
index 711c14247ca..7500f7f7997 100644
--- a/src/NHibernate/Mapping/ManyToOne.cs
+++ b/src/NHibernate/Mapping/ManyToOne.cs
@@ -9,24 +9,11 @@ namespace NHibernate.Mapping
[Serializable]
public class ManyToOne : ToOne
{
- private readonly string _entityName;
-
- ///
- /// Construct a many-to-one mapping.
- ///
- /// The table.
- /// The association owner.
- public ManyToOne(Table table, PersistentClass owner) : base(table)
- {
- _entityName = owner?.EntityName;
- }
-
///
///
///
///
- [Obsolete("Use overload with owner instead.")]
- public ManyToOne(Table table) : this(table, null)
+ public ManyToOne(Table table) : base(table)
{
}
@@ -54,7 +41,7 @@ public bool IsLogicalOneToOne
get { return isLogicalOneToOne; }
set { isLogicalOneToOne = value; }
}
-
+
public string PropertyName { get; set; }
private IType type;
@@ -64,9 +51,8 @@ public override IType Type
{
if (type == null)
{
- type = TypeFactory.ManyToOne(
- ReferencedEntityName, ReferencedPropertyName, IsLazy, UnwrapProxy,
- IsIgnoreNotFound, isLogicalOneToOne, _entityName, PropertyName);
+ type =
+ TypeFactory.ManyToOne(ReferencedEntityName, ReferencedPropertyName, IsLazy, UnwrapProxy, IsIgnoreNotFound, isLogicalOneToOne, PropertyName);
}
return type;
}
diff --git a/src/NHibernate/Mapping/OneToMany.cs b/src/NHibernate/Mapping/OneToMany.cs
index 0d92d564d66..b349e4df98b 100644
--- a/src/NHibernate/Mapping/OneToMany.cs
+++ b/src/NHibernate/Mapping/OneToMany.cs
@@ -23,9 +23,7 @@ public OneToMany(PersistentClass owner)
private EntityType EntityType
{
- get { return TypeFactory.ManyToOne(
- ReferencedEntityName, null, false, false,
- IsIgnoreNotFound, false, null, null); }
+ get { return TypeFactory.ManyToOne(ReferencedEntityName, null, false, false, IsIgnoreNotFound, false, null); }
}
public bool IsIgnoreNotFound
diff --git a/src/NHibernate/Type/ManyToOneType.cs b/src/NHibernate/Type/ManyToOneType.cs
index 00b54cdaf0c..172bc8f1b99 100644
--- a/src/NHibernate/Type/ManyToOneType.cs
+++ b/src/NHibernate/Type/ManyToOneType.cs
@@ -1,6 +1,7 @@
using System;
using System.Data.Common;
using NHibernate.Engine;
+using NHibernate.Proxy;
using NHibernate.SqlTypes;
using NHibernate.Util;
@@ -14,7 +15,6 @@ public partial class ManyToOneType : EntityType
{
private readonly bool ignoreNotFound;
private readonly bool isLogicalOneToOne;
- private readonly string _entityName;
public ManyToOneType(string className)
: this(className, false)
@@ -30,41 +30,18 @@ public ManyToOneType(string className, bool lazy)
}
//Since 5.3
- [Obsolete("Use Constructor with owner property name and property name")]
+ [Obsolete("Use Constructor with property name")]
public ManyToOneType(string entityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne)
- : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, null)
+ : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null)
{
}
- //Since 5.3.6
- [Obsolete("Use Constructor with owner entity name")]
public ManyToOneType(string entityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne, string propertyName)
- : this(entityName, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, propertyName)
- {
- }
-
- ///
- /// Build a many-to-one relation.
- ///
- /// The referenced entity name.
- /// The property-ref name, or if we reference
- /// the PK of the associated entity.
- /// Is the association lazily loaded?
- /// Is unwrapping of proxies allowed for this association; unwrapping says to return
- /// the "implementation target" of lazy proxies; typically only possible with lazy="no-proxy".
- /// for throwing an exception if the referenced
- /// entity is missing in the database, for yielding instead.
- ///
- /// The property owner entity name.
- /// The property name.
- public ManyToOneType(string referencedEntityName, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy,
- bool ignoreNotFound, bool isLogicalOneToOne, string entityName, string propertyName)
- : base(referencedEntityName, uniqueKeyPropertyName, !lazy, unwrapProxy)
+ : base(entityName, uniqueKeyPropertyName, !lazy, unwrapProxy)
{
this.ignoreNotFound = ignoreNotFound;
this.isLogicalOneToOne = isLogicalOneToOne;
PropertyName = propertyName;
- _entityName = entityName;
}
public override int GetColumnSpan(IMapping mapping)
@@ -185,19 +162,24 @@ private bool IsIdentifier(object value, ISessionImplementor session)
public override bool IsNull(object owner, ISessionImplementor session)
{
- if (IsNullable && !string.IsNullOrEmpty(PropertyName) && owner != null)
- {
- var ownerPersister = session.Factory.GetEntityPersister(_entityName);
- var id = session.GetContextEntityIdentifier(owner);
- if (id == null)
- return false;
+ if (!IsNullable || string.IsNullOrEmpty(PropertyName) || owner == null)
+ return false;
- var entityKey = session.GenerateEntityKey(id, ownerPersister);
+ var entityKey = GetEntityKey(owner, session);
+ if (entityKey == null)
+ return false;
- return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
- }
+ return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
+ }
- return false;
+ private static EntityKey GetEntityKey(object owner, ISessionImplementor session)
+ {
+ var entry = session.PersistenceContext.GetEntry(owner);
+ if (entry != null)
+ return entry.EntityKey;
+ if (owner is INHibernateProxy proxy)
+ return session.GenerateEntityKey(proxy.HibernateLazyInitializer.Identifier, session.Factory.GetEntityPersister(proxy.HibernateLazyInitializer.EntityName));
+ return null;
}
public override object Disassemble(object value, ISessionImplementor session, object owner)
diff --git a/src/NHibernate/Type/TypeFactory.cs b/src/NHibernate/Type/TypeFactory.cs
index eb33be5997a..271b85ff4ea 100644
--- a/src/NHibernate/Type/TypeFactory.cs
+++ b/src/NHibernate/Type/TypeFactory.cs
@@ -957,39 +957,18 @@ public static EntityType ManyToOne(string persistentClass, bool lazy)
///
/// A many-to-one association type for the given class and cascade style.
///
- /// The referenced class.
- /// The property-ref name, or if we reference
- /// the PK of the associated entity.
- /// Is the association lazily loaded?
- /// Is unwrapping of proxies allowed for this association; unwrapping says to return
- /// the "implementation target" of lazy proxies; typically only possible with lazy="no-proxy".
- /// for throwing an exception if the referenced
- /// entity is missing in the database, for yielding instead.
- ///
- /// The property owner entity name.
- /// The property name.
- public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy,
- bool ignoreNotFound, bool isLogicalOneToOne, string entityName, string propertyName)
- {
- return new ManyToOneType(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, entityName, propertyName);
- }
-
- ///
- /// A many-to-one association type for the given class and cascade style.
- ///
- [Obsolete("Use ManyToOne with owner entity name")]
public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne, string propertyName)
{
- return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, propertyName);
+ return new ManyToOneType(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, propertyName);
}
///
/// A many-to-one association type for the given class and cascade style.
///
- [Obsolete("Use ManyToOne with owner entity name and propertyName")]
+ [Obsolete("Use ManyToOne with propertyName")]
public static EntityType ManyToOne(string persistentClass, string uniqueKeyPropertyName, bool lazy, bool unwrapProxy, bool ignoreNotFound, bool isLogicalOneToOne)
{
- return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null, null);
+ return ManyToOne(persistentClass, uniqueKeyPropertyName, lazy, unwrapProxy, ignoreNotFound, isLogicalOneToOne, null);
}
public static CollectionType Array(string role, string propertyRef, System.Type elementClass)