diff --git a/src/EFCore/Infrastructure/AnnotatableBuilder.cs b/src/EFCore/Infrastructure/AnnotatableBuilder.cs index 06d48c367f3..7bb11fdfdaf 100644 --- a/src/EFCore/Infrastructure/AnnotatableBuilder.cs +++ b/src/EFCore/Infrastructure/AnnotatableBuilder.cs @@ -195,7 +195,7 @@ public virtual AnnotatableBuilder MergeAnnotationsFrom annotation.Name, annotation.Value, configurationSource, - canOverrideSameSource: false) + canOverrideSameSource: true) ?? builder; } } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs index 203c413dee6..d7a8c680297 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs @@ -471,6 +471,9 @@ public override TestPropertyBuilder IsRequired(bool isRequired = true public override TestPropertyBuilder HasMaxLength(int maxLength) => Wrap(PropertyBuilder.HasMaxLength(maxLength)); + public override TestPropertyBuilder HasPrecision(int precision) + => Wrap(PropertyBuilder.HasPrecision(precision)); + public override TestPropertyBuilder HasPrecision(int precision, int scale) => Wrap(PropertyBuilder.HasPrecision(precision, scale)); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs index 262aa29ec18..8235121bb6f 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs @@ -551,6 +551,9 @@ public override TestPropertyBuilder IsRequired(bool isRequired = true public override TestPropertyBuilder HasMaxLength(int maxLength) => Wrap(PropertyBuilder.HasMaxLength(maxLength)); + public override TestPropertyBuilder HasPrecision(int precision) + => Wrap(PropertyBuilder.HasPrecision(precision)); + public override TestPropertyBuilder HasPrecision(int precision, int scale) => Wrap(PropertyBuilder.HasPrecision(precision, scale)); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs index 9f262554222..dcd17556d7f 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs @@ -374,6 +374,7 @@ public abstract class TestPropertyBuilder public abstract TestPropertyBuilder HasAnnotation(string annotation, object? value); public abstract TestPropertyBuilder IsRequired(bool isRequired = true); public abstract TestPropertyBuilder HasMaxLength(int maxLength); + public abstract TestPropertyBuilder HasPrecision(int precision); public abstract TestPropertyBuilder HasPrecision(int precision, int scale); public abstract TestPropertyBuilder IsUnicode(bool unicode = true); public abstract TestPropertyBuilder IsRowVersion(); diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs index c4b5e2d14ac..c3338ce8745 100644 --- a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs @@ -9,6 +9,100 @@ public abstract partial class ModelBuilderTest { public abstract class OwnedTypesTestBase : ModelBuilderTestBase { + [ConditionalTheory] // Issue #28091 + [InlineData(16, 2, 16, 4, 16, 4, 16, 4, 16, 4)] + [InlineData(16, 2, 17, 4, 17, 4, 17, 4, 17, 4)] + [InlineData(null, null, 16, 4, 16, 4, 16, 4, 16, 4)] + [InlineData(null, null, 16, 4, 15, 3, 14, 2, 13, 1)] + [InlineData(null, null, 16, null, 15, null, 14, null, 13, null)] + [InlineData(17, null, 16, null, 15, null, 14, null, 13, null)] + [InlineData(17, 5, 16, 4, 15, 3, 14, 2, 13, 1)] + [InlineData(17, 5, null, null, null, null, null, null, null, null)] + public virtual void Precision_and_scale_for_property_type_used_in_owned_types_can_be_overwritten( + int? defaultPrecision, + int? defaultScale, + int? mainPrecision, + int? mainScale, + int? otherPrecision, + int? otherScale, + int? onePrecision, + int? oneScale, + int? manyPrecision, + int? manyScale) + { + var modelBuilder = CreateModelBuilder( + c => + { + if (defaultPrecision.HasValue) + { + if (defaultScale.HasValue) + { + c.Properties().HavePrecision(defaultPrecision.Value, defaultScale.Value); + } + else + { + c.Properties().HavePrecision(defaultPrecision.Value); + } + } + }); + + modelBuilder.Entity( + b => + { + HasPrecision(b.Property(x => x.Number), mainPrecision, mainScale); + b.OwnsOne( + b => b.OwnedEntity, b => + { + HasPrecision(b.Property(x => x.Number), onePrecision, oneScale); + }); + }); + + modelBuilder.Entity( + b => + { + HasPrecision(b.Property(x => x.Number), otherPrecision, otherScale); + b.OwnsMany( + b => b.OwnedEntities, b => + { + HasPrecision(b.Property(x => x.Number), manyPrecision, manyScale); + }); + }); + + var model = modelBuilder.FinalizeModel(); + + var mainType = model.FindEntityType(typeof(MainOtter))!; + var otherType = model.FindEntityType(typeof(OtherOtter))!; + var oneType = model.FindEntityType(typeof(OwnedOtter), nameof(MainOtter.OwnedEntity), mainType)!; + var manyType = model.FindEntityType(typeof(OwnedOtter), nameof(OtherOtter.OwnedEntities), otherType)!; + + Assert.Equal(mainPrecision ?? defaultPrecision, mainType.FindProperty(nameof(MainOtter.Number))!.GetPrecision()); + Assert.Equal(mainScale ?? defaultScale, mainType.FindProperty(nameof(MainOtter.Number))!.GetScale()); + + Assert.Equal(otherPrecision ?? defaultPrecision, otherType.FindProperty(nameof(OtherOtter.Number))!.GetPrecision()); + Assert.Equal(otherScale ?? defaultScale, otherType.FindProperty(nameof(OtherOtter.Number))!.GetScale()); + + Assert.Equal(onePrecision ?? defaultPrecision, oneType.FindProperty(nameof(OwnedOtter.Number))!.GetPrecision()); + Assert.Equal(oneScale ?? defaultScale, oneType.FindProperty(nameof(OwnedOtter.Number))!.GetScale()); + + Assert.Equal(manyPrecision ?? defaultPrecision, manyType.FindProperty(nameof(OwnedOtter.Number))!.GetPrecision()); + Assert.Equal(manyScale ?? defaultScale, manyType.FindProperty(nameof(OwnedOtter.Number))!.GetScale()); + + void HasPrecision(TestPropertyBuilder testPropertyBuilder, int? precision, int? scale) + { + if (precision.HasValue) + { + if (scale.HasValue) + { + testPropertyBuilder.HasPrecision(precision.Value, scale.Value); + } + else + { + testPropertyBuilder.HasPrecision(precision.Value); + } + } + } + } + [ConditionalFact] public virtual void Can_configure_owned_type() { diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Tests/ModelBuilding/TestModel.cs index e73dbc5c7f1..f0e81f97409 100644 --- a/test/EFCore.Tests/ModelBuilding/TestModel.cs +++ b/test/EFCore.Tests/ModelBuilding/TestModel.cs @@ -1232,4 +1232,23 @@ protected class Discount public int? StoreId { get; set; } public Store? Store { get; set; } } + + protected class MainOtter + { + public Guid Id { get; set; } + public decimal Number { get; set; } + public OwnedOtter OwnedEntity { get; set; } = null!; + } + + protected class OtherOtter + { + public Guid Id { get; set; } + public decimal Number { get; set; } + public List OwnedEntities { get; } = new(); + } + + protected class OwnedOtter + { + public decimal Number { get; set; } + } }