diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/FixtureByCode.cs
new file mode 100644
index 00000000000..5fcfcb3d918
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/FixtureByCode.cs
@@ -0,0 +1,32 @@
+using System.Linq;
+using NHibernate.Cfg;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.GH3607
+{
+ ///
+ /// By code mapping serialization failure since v5.4.1. Adapted from .
+ ///
+ [TestFixture]
+ public class FixtureByCode : TestCaseMappingByCode
+ {
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ModelMapper();
+ mapper.AddMappings(new[] { typeof(OrderMapping), typeof(LineItemMapping), typeof(LineItemDataMapping) });
+ return mapper.CompileMappingForAllExplicitlyAddedEntities();
+ }
+
+ [Test]
+ public void SerializeMappingToXml()
+ {
+ var mapping = GetMappings();
+ string serialized = "";
+ Assert.That(() => serialized = mapping.AsString(), Throws.Nothing, "Mapping serialization failure");
+ var config = new Configuration();
+ Assert.That(() => config.AddXml(serialized), Throws.Nothing, "Configuration with serialized mapping has failed");
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/LineItem.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItem.cs
new file mode 100644
index 00000000000..367a7339be5
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItem.cs
@@ -0,0 +1,14 @@
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class LineItem
+{
+ public virtual int Id { get; set; }
+
+ public virtual Order ParentOrder { get; set; }
+
+ public virtual string ItemName { get; set; }
+
+ public virtual decimal Amount { get; set; }
+
+ public virtual LineItemData Data { get; set; }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemData.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemData.cs
new file mode 100644
index 00000000000..e89dc4e3f08
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemData.cs
@@ -0,0 +1,8 @@
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class LineItemData
+{
+ public virtual LineItem LineItem { get; set; }
+
+ public virtual string Data { get; set; }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemDataMapping.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemDataMapping.cs
new file mode 100644
index 00000000000..be1bb6fc22a
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemDataMapping.cs
@@ -0,0 +1,13 @@
+using NHibernate.Mapping.ByCode.Conformist;
+
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class LineItemDataMapping : ClassMapping
+{
+ public LineItemDataMapping()
+ {
+ OneToOne(x => x.LineItem, m => m.Constrained(true));
+
+ Property(x => x.Data);
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemMapping.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemMapping.cs
new file mode 100644
index 00000000000..bfa5ec953c1
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/LineItemMapping.cs
@@ -0,0 +1,20 @@
+using NHibernate.Mapping.ByCode;
+using NHibernate.Mapping.ByCode.Conformist;
+
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class LineItemMapping : ClassMapping
+{
+ public LineItemMapping()
+ {
+ Id(x => x.Id, m => m.Generator(new IdentityGeneratorDef()));
+
+ Property(x => x.ItemName);
+
+ Property(x => x.Amount);
+
+ ManyToOne(x => x.ParentOrder);
+
+ ManyToOne(x => x.Data);
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/Order.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/Order.cs
new file mode 100644
index 00000000000..87e11b62dae
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/Order.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class Order
+{
+ public virtual int Id { get; set; }
+
+ public virtual DateTime CreatedDate { get; set; }
+
+ public virtual ISet Items { get; protected set; } = new HashSet();
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3607/OrderMapping.cs b/src/NHibernate.Test/NHSpecificTest/GH3607/OrderMapping.cs
new file mode 100644
index 00000000000..a14929fcebd
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3607/OrderMapping.cs
@@ -0,0 +1,21 @@
+using NHibernate.Mapping.ByCode;
+using NHibernate.Mapping.ByCode.Conformist;
+
+namespace NHibernate.Test.NHSpecificTest.GH3607;
+
+public class OrderMapping : ClassMapping
+{
+ public OrderMapping()
+ {
+ Table("`Order`");
+ Id(x => x.Id, m => m.Generator(new IdentityGeneratorDef()));
+
+ Property(x => x.CreatedDate);
+
+ Set(x => x.Items, m =>
+ {
+ m.Inverse(true);
+ m.OptimisticLock(true);
+ }, a => a.OneToMany());
+ }
+}
diff --git a/src/NHibernate/Cfg/MappingSchema/HbmOneToOne.cs b/src/NHibernate/Cfg/MappingSchema/HbmOneToOne.cs
index e0740e17937..aec82a44ee4 100644
--- a/src/NHibernate/Cfg/MappingSchema/HbmOneToOne.cs
+++ b/src/NHibernate/Cfg/MappingSchema/HbmOneToOne.cs
@@ -18,9 +18,13 @@ public string Access
get { return access; }
}
+ // 6.0 Todo : remove XmlIgnore after removing the setter. See #3607 fix.
+ [XmlIgnore]
public bool OptimisticLock
{
get => optimisticlock;
+ // Since v5.4.10
+ [Obsolete("Providing a setter for OptimisticLock was unintended and will be removed.")]
set => optimisticlock = value;
}