From 017f5d294e659ba228d6315ef3534c4bea2b3fa1 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 7 Jun 2023 05:53:43 +0000 Subject: [PATCH] Fix conventions not applying to members of (#608) See #607 +semver:fix --- .editorconfig | 11 +- .../NaturalIdManyToOneConventionTests.cs | 196 +++++++++++++++ .../NaturalIdPropertyConventionTests.cs | 232 ++++++++++++++++++ src/FluentNHibernate/Mapping/NaturalIdPart.cs | 26 +- src/FluentNHibernate/Mapping/PropertyPart.cs | 4 +- .../Visitors/DefaultMappingModelVisitor.cs | 7 +- 6 files changed, 453 insertions(+), 23 deletions(-) create mode 100644 src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdManyToOneConventionTests.cs create mode 100644 src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdPropertyConventionTests.cs diff --git a/.editorconfig b/.editorconfig index 49eb1ac3b..0f51d3260 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,10 @@ +root = true ; This file is for unifying the coding style for different editors and IDEs. ; More information at http://EditorConfig.org -root = true [*] -end_of_line = CRLF +end_of_line = crlf [*.ps1] indent_style = space @@ -17,7 +17,10 @@ insert_final_newline = true csharp_style_namespace_declarations = file_scoped -dotnet_diagnostic.IDE0161.severity = warning +dotnet_diagnostic.ide0161.severity = warning + +# ReSharper properties +resharper_default_private_modifier = implicit [*.cake] indent_style = space @@ -25,4 +28,4 @@ indent_size = 4 [*.js] indent_style = tab -indent_size = 2 \ No newline at end of file +indent_size = 2 diff --git a/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdManyToOneConventionTests.cs b/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdManyToOneConventionTests.cs new file mode 100644 index 000000000..e0a53d5da --- /dev/null +++ b/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdManyToOneConventionTests.cs @@ -0,0 +1,196 @@ +using System; +using System.Linq; +using FluentNHibernate.Automapping.TestFixtures; +using FluentNHibernate.Conventions.Helpers.Builders; +using FluentNHibernate.Conventions.Instances; +using FluentNHibernate.Mapping; +using FluentNHibernate.MappingModel; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.ConventionsTests.ApplyingToModel; + +[TestFixture] +public class NaturalIdManyToOneConventionTests +{ + private PersistenceModel model; + + [SetUp] + public void CreatePersistenceModel() + { + model = new PersistenceModel(); + } + + [Test] + public void ShouldSetAccessProperty() + { + Convention(x => x.Access.Property()); + + VerifyModel(x => x.Access.ShouldEqual("property")); + } + + [Test] + public void ShouldSetCascadeProperty() + { + Convention(x => x.Cascade.None()); + + VerifyModel(x => x.Cascade.ShouldEqual("none")); + } + + [Test] + public void ShouldSetClassProperty() + { + Convention(x => x.CustomClass(typeof(int))); + + VerifyModel(x => x.Class.GetUnderlyingSystemType().ShouldEqual(typeof(int))); + } + + [Test] + public void ShouldSetColumnProperty() + { + Convention(x => x.Column("xxx")); + + VerifyModel(x => x.Columns.First().Name.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetFetchProperty() + { + Convention(x => x.Fetch.Select()); + + VerifyModel(x => x.Fetch.ShouldEqual("select")); + } + + [Test] + public void ShouldSetIndexProperty() + { + Convention(x => x.Index("value")); + + VerifyModel(x => x.Columns.First().Index.ShouldEqual("value")); + } + + [Test] + public void ShouldSetInsertProperty() + { + Convention(x => x.Insert()); + + VerifyModel(x => x.Insert.ShouldBeTrue()); + } + + [Test] + public void ShouldSetLazyProperty() + { + Convention(x => x.LazyLoad()); + + VerifyModel(x => x.Lazy.ShouldEqual(Laziness.Proxy.ToString())); + } + + [Test] + public void ShouldSetNotFoundProperty() + { + Convention(x => x.NotFound.Ignore()); + + VerifyModel(x => x.NotFound.ShouldEqual("ignore")); + } + + [Test] + public void ShouldSetNullableProperty() + { + Convention(x => x.Nullable()); + + VerifyModel(x => x.Columns.First().NotNull.ShouldBeFalse()); + } + + [Test] + public void ShouldSetPropertyRefProperty() + { + Convention(x => x.PropertyRef("xxx")); + + VerifyModel(x => x.PropertyRef.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetReadOnlyProperty() + { + Convention(x => x.ReadOnly()); + + VerifyModel(x => + { + x.Insert.ShouldBeFalse(); + x.Update.ShouldBeFalse(); + }); + } + + [Test] + public void ShouldSetUniqueProperty() + { + Convention(x => x.Unique()); + + VerifyModel(x => x.Columns.First().Unique.ShouldBeTrue()); + } + + [Test] + public void ShouldSetUniqueKeyProperty() + { + Convention(x => x.UniqueKey("xxx")); + + VerifyModel(x => x.Columns.First().UniqueKey.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetUpdateProperty() + { + Convention(x => x.Update()); + + VerifyModel(x => x.Update.ShouldBeTrue()); + } + + [Test] + public void ShouldSetForeignKeyProperty() + { + Convention(x => x.ForeignKey("xxx")); + + VerifyModel(x => x.ForeignKey.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetFormulaProperty() + { + Convention(x => x.Formula("xxx")); + + VerifyModel(x => x.Formula.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetOptimisticLockProperty() + { + Convention(x => x.OptimisticLock()); + + VerifyModel(x => x.OptimisticLock.ShouldBeTrue()); + } + + #region Helpers + + private void Convention(Action convention) + { + model.Conventions.Add(new ReferenceConventionBuilder().Always(convention)); + } + + private void VerifyModel(Action modelVerification) + { + var classMap = new ClassMap(); + classMap.Id(x => x.Id); + var map = classMap.NaturalId().Reference(x => x.Parent); + + model.Add(classMap); + + var generatedModels = model.BuildMappings(); + var modelInstance = generatedModels + .SelectMany(x => x.Classes) + .First(x => x.Type == typeof(ExampleClass)) + .NaturalId.ManyToOnes.First(); + + modelVerification(modelInstance); + } + + #endregion +} diff --git a/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdPropertyConventionTests.cs b/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdPropertyConventionTests.cs new file mode 100644 index 000000000..611f23032 --- /dev/null +++ b/src/FluentNHibernate.Testing/ConventionsTests/ApplyingToModel/NaturalIdPropertyConventionTests.cs @@ -0,0 +1,232 @@ +using System; +using System.Linq; +using FluentNHibernate.Automapping.TestFixtures; +using FluentNHibernate.Conventions.Helpers.Builders; +using FluentNHibernate.Conventions.Instances; +using FluentNHibernate.Mapping; +using FluentNHibernate.MappingModel; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.ConventionsTests.ApplyingToModel; + +[TestFixture] +public class NaturalIdPropertyConventionTests +{ + private PersistenceModel model; + + [SetUp] + public void CreatePersistenceModel() + { + model = new PersistenceModel(); + } + + [Test] + public void ShouldSetAccessProperty() + { + Convention(x => x.Access.Property()); + + VerifyModel(x => x.Access.ShouldEqual("property")); + } + + [Test] + public void ShouldSetColumnNameProperty() + { + Convention(x => x.Column("yyy")); + + VerifyModel(x => + { + x.Columns.Count().ShouldEqual(1); + x.Columns.First().Name.ShouldEqual("yyy"); + }); + } + + [Test] + public void ShouldSetSqlTypeProperty() + { + Convention(x => x.CustomSqlType("type")); + + VerifyModel(x => x.Columns.First().SqlType.ShouldEqual("type")); + } + + [Test] + public void ShouldSetTypeProperty() + { + Convention(x => x.CustomType()); + + VerifyModel(x => x.Type.GetUnderlyingSystemType().ShouldEqual(typeof(int))); + } + + [Test] + public void ShouldSetFormulaProperty() + { + Convention(x => x.Formula("xxx")); + + VerifyModel(x => x.Formula.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetGeneratedProperty() + { + Convention(x => x.Generated.Never()); + + VerifyModel(x => x.Generated.ShouldEqual("never")); + } + + [Test] + public void ShouldSetInsertProperty() + { + Convention(x => x.Insert()); + + VerifyModel(x => x.Insert.ShouldBeTrue()); + } + + [Test] + public void ShouldSetNullableProperty() + { + Convention(x => x.Nullable()); + + VerifyModel(x => x.Columns.First().NotNull.ShouldBeFalse()); + } + + [Test] + public void ShouldSetOptimisticLockProperty() + { + Convention(x => x.OptimisticLock()); + + VerifyModel(x => x.OptimisticLock.ShouldBeTrue()); + } + + [Test] + public void ReadOnlyShouldntOverwriteInsert() + { + Convention(x => x.ReadOnly()); + + VerifyModel(x => x.Insert.ShouldBeFalse()); + } + + [Test] + public void ReadOnlyShouldntOverwriteUpdate() + { + Convention(x => x.ReadOnly()); + + VerifyModel(x => x.Update.ShouldBeFalse()); + } + + [Test] + public void ShouldSetReadOnlyProperty() + { + Convention(x => x.ReadOnly()); + + VerifyModel(x => + { + x.Insert.ShouldBeFalse(); + x.Update.ShouldBeFalse(); + }); + } + + [Test] + public void ShouldSetUniqueProperty() + { + Convention(x => x.Unique()); + + VerifyModel(x => x.Columns.First().Unique.ShouldBeTrue()); + } + + [Test] + public void ShouldSetUniqueKeyProperty() + { + Convention(x => x.UniqueKey("test")); + + VerifyModel(x => x.Columns.First().UniqueKey.ShouldEqual("test")); + } + + [Test] + public void ShouldSetUpdateProperty() + { + Convention(x => x.Update()); + + VerifyModel(x => x.Update.ShouldBeTrue()); + } + + [Test] + public void ShouldSetLengthProperty() + { + Convention(x => x.Length(10)); + + VerifyModel(x => x.Columns.First().Length.ShouldEqual(10)); + } + + [Test] + public void ShouldSetLazyProperty() + { + Convention(x => x.LazyLoad()); + + VerifyModel(x => x.Lazy.ShouldBeTrue()); + } + + [Test] + public void ShouldSetIndexProperty() + { + Convention(x => x.Index("xxx")); + + VerifyModel(x => x.Columns.First().Index.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetPrecisionProperty() + { + Convention(x => x.Precision(200)); + + VerifyModel(x => x.Columns.First().Precision.ShouldEqual(200)); + } + + [Test] + public void ShouldSetScaleProperty() + { + Convention(x => x.Scale(200)); + + VerifyModel(x => x.Columns.First().Scale.ShouldEqual(200)); + } + + [Test] + public void ShouldSetDefaultProperty() + { + Convention(x => x.Default("xxx")); + + VerifyModel(x => x.Columns.First().Default.ShouldEqual("xxx")); + } + + [Test] + public void ShouldSetCheckProperty() + { + Convention(x => x.Check("check")); + + VerifyModel(x => x.Columns.First().Check.ShouldEqual("check")); + } + + #region Helpers + + private void Convention(Action convention) + { + model.Conventions.Add(new PropertyConventionBuilder().Always(convention)); + } + + private void VerifyModel(Action modelVerification) + { + var classMap = new ClassMap(); + classMap.Id(x => x.Id); + var map = classMap.NaturalId().Property(x => x.LineOne); + + model.Add(classMap); + + var generatedModels = model.BuildMappings(); + var modelInstance = generatedModels + .SelectMany(x => x.Classes) + .First(x => x.Type == typeof(ExampleClass)) + .NaturalId.Properties.First(); + + modelVerification(modelInstance); + } + + #endregion +} diff --git a/src/FluentNHibernate/Mapping/NaturalIdPart.cs b/src/FluentNHibernate/Mapping/NaturalIdPart.cs index aa415be94..d662cb293 100644 --- a/src/FluentNHibernate/Mapping/NaturalIdPart.cs +++ b/src/FluentNHibernate/Mapping/NaturalIdPart.cs @@ -10,9 +10,9 @@ namespace FluentNHibernate.Mapping; public class NaturalIdPart : INaturalIdMappingProvider { - readonly AttributeStore attributes = new AttributeStore(); - readonly IList properties = new List(); - readonly IList manyToOnes = new List(); + readonly AttributeStore attributes = new(); + readonly List properties = new(); + readonly List manyToOnes = new(); bool nextBool = true; /// @@ -22,8 +22,7 @@ public class NaturalIdPart : INaturalIdMappingProvider /// The natural id part fluent interface public NaturalIdPart Property(Expression> expression) { - var member = expression.ToMember(); - return Property(expression, member.Name); + return Property(expression, null); } /// @@ -40,15 +39,10 @@ public NaturalIdPart Property(Expression> expression, string protected virtual NaturalIdPart Property(Member member, string columnName) { - var key = new PropertyMapping(); - key.Set(x => x.Name, Layer.Defaults, member.Name); - key.Set(x => x.Type, Layer.Defaults, new TypeReference(member.PropertyType)); - var columnMapping = new ColumnMapping(); - columnMapping.Set(x => x.Name, Layer.Defaults, columnName); - key.AddColumn(Layer.UserSupplied, columnMapping); - - properties.Add(key); - + var property = new PropertyPart(member, typeof(T)); + if (!string.IsNullOrEmpty(columnName)) + property.Column(columnName); + properties.Add(property); return this; } @@ -120,9 +114,9 @@ NaturalIdMapping INaturalIdMappingProvider.GetNaturalIdMapping() { var mapping = new NaturalIdMapping(attributes.Clone()); - properties.Each(mapping.AddProperty); + properties.Each(p => mapping.AddProperty(((IPropertyMappingProvider)p).GetPropertyMapping())); manyToOnes.Each(mapping.AddReference); return mapping; } -} +} diff --git a/src/FluentNHibernate/Mapping/PropertyPart.cs b/src/FluentNHibernate/Mapping/PropertyPart.cs index 2f8410cf3..13f37809f 100644 --- a/src/FluentNHibernate/Mapping/PropertyPart.cs +++ b/src/FluentNHibernate/Mapping/PropertyPart.cs @@ -325,7 +325,7 @@ PropertyMapping IPropertyMappingProvider.GetPropertyMapping() Member = member }; - if (columns.Count() == 0 && !mapping.IsSpecified("Formula")) + if (columns.Count == 0 && !mapping.IsSpecified("Formula")) { var columnMapping = new ColumnMapping(columnAttributes.Clone()); columnMapping.Set(x => x.Name, Layer.Defaults, member.Name); @@ -361,4 +361,4 @@ TypeReference GetDefaultType() return type; } -} +} diff --git a/src/FluentNHibernate/Visitors/DefaultMappingModelVisitor.cs b/src/FluentNHibernate/Visitors/DefaultMappingModelVisitor.cs index e7acc546f..bebbe4b81 100644 --- a/src/FluentNHibernate/Visitors/DefaultMappingModelVisitor.cs +++ b/src/FluentNHibernate/Visitors/DefaultMappingModelVisitor.cs @@ -84,6 +84,11 @@ public override void Visit(AnyMapping mapping) mapping.AcceptVisitor(this); } + public override void Visit(NaturalIdMapping mapping) + { + mapping.AcceptVisitor(this); + } + public override void Visit(ClassMapping classMapping) { classMapping.AcceptVisitor(this); @@ -179,4 +184,4 @@ public override void Visit(KeyManyToOneMapping mapping) mapping.AcceptVisitor(this); } -} +}