From a6f0c52201b6d4fc27cf3aeba2c588c49e37c71d Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Thu, 3 Sep 2020 14:55:20 -0700 Subject: [PATCH] Propagate identity seed and increment to sharing columns Fixes #22358 --- .../Extensions/SqlServerPropertyExtensions.cs | 48 ++++++++++++++++--- .../Internal/SqlServerModelValidator.cs | 12 ++--- .../Internal/SqlServerValueGeneratorCache.cs | 3 +- .../SqlServerModelValidatorTest.cs | 12 ++++- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs index 5a51c533096..d3bd5a49c98 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs @@ -24,6 +24,15 @@ public static class SqlServerPropertyExtensions /// The property. /// The name to use for the hi-lo sequence. public static string GetHiLoSequenceName([NotNull] this IProperty property) + => (string)property[SqlServerAnnotationNames.HiLoSequenceName]; + + /// + /// Returns the name to use for the hi-lo sequence. + /// + /// The property. + /// The identifier of the store object. + /// The name to use for the hi-lo sequence. + public static string GetHiLoSequenceName([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqlServerAnnotationNames.HiLoSequenceName); if (annotation != null) @@ -31,10 +40,9 @@ public static string GetHiLoSequenceName([NotNull] this IProperty property) return (string)annotation.Value; } - var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty( - StoreObjectIdentifier.Table(property.DeclaringEntityType.GetTableName(), property.DeclaringEntityType.GetSchema())); + var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject); return sharedTableRootProperty != null - ? sharedTableRootProperty.GetHiLoSequenceSchema() + ? sharedTableRootProperty.GetHiLoSequenceName(storeObject) : null; } @@ -82,6 +90,15 @@ public static string SetHiLoSequenceName( /// The property. /// The schema to use for the hi-lo sequence. public static string GetHiLoSequenceSchema([NotNull] this IProperty property) + => (string)property[SqlServerAnnotationNames.HiLoSequenceSchema]; + + /// + /// Returns the schema to use for the hi-lo sequence. + /// + /// The property. + /// The identifier of the store object. + /// The schema to use for the hi-lo sequence. + public static string GetHiLoSequenceSchema([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqlServerAnnotationNames.HiLoSequenceSchema); if (annotation != null) @@ -89,10 +106,9 @@ public static string GetHiLoSequenceSchema([NotNull] this IProperty property) return (string)annotation.Value; } - var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty( - StoreObjectIdentifier.Table(property.DeclaringEntityType.GetTableName(), property.DeclaringEntityType.GetSchema())); + var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject); return sharedTableRootProperty != null - ? sharedTableRootProperty.GetHiLoSequenceSchema() + ? sharedTableRootProperty.GetHiLoSequenceSchema(storeObject) : null; } @@ -137,6 +153,7 @@ public static string SetHiLoSequenceSchema( /// /// Finds the in the model to use for the hi-lo pattern. /// + /// The property. /// The sequence to use, or if no sequence exists in the model. public static ISequence FindHiLoSequence([NotNull] this IProperty property) { @@ -151,6 +168,25 @@ public static ISequence FindHiLoSequence([NotNull] this IProperty property) return model.FindSequence(sequenceName, sequenceSchema); } + /// + /// Finds the in the model to use for the hi-lo pattern. + /// + /// The property. + /// The identifier of the store object. + /// The sequence to use, or if no sequence exists in the model. + public static ISequence FindHiLoSequence([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) + { + var model = property.DeclaringEntityType.Model; + + var sequenceName = property.GetHiLoSequenceName(storeObject) + ?? model.GetHiLoSequenceName(); + + var sequenceSchema = property.GetHiLoSequenceSchema(storeObject) + ?? model.GetHiLoSequenceSchema(); + + return model.FindSequence(sequenceName, sequenceSchema); + } + /// /// Returns the identity seed. /// diff --git a/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs b/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs index d5cce0f766c..34fdcfe6fac 100644 --- a/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs +++ b/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs @@ -293,8 +293,8 @@ protected override void ValidateCompatible( switch (propertyStrategy) { case SqlServerValueGenerationStrategy.IdentityColumn: - var increment = property.GetIdentityIncrement(); - var duplicateIncrement = duplicateProperty.GetIdentityIncrement(); + var increment = property.GetIdentityIncrement(storeObject); + var duplicateIncrement = duplicateProperty.GetIdentityIncrement(storeObject); if (increment != duplicateIncrement) { throw new InvalidOperationException( @@ -307,8 +307,8 @@ protected override void ValidateCompatible( storeObject.DisplayName())); } - var seed = property.GetIdentitySeed(); - var duplicateSeed = duplicateProperty.GetIdentitySeed(); + var seed = property.GetIdentitySeed(storeObject); + var duplicateSeed = duplicateProperty.GetIdentitySeed(storeObject); if (seed != duplicateSeed) { throw new InvalidOperationException( @@ -323,8 +323,8 @@ protected override void ValidateCompatible( break; case SqlServerValueGenerationStrategy.SequenceHiLo: - if (property.GetHiLoSequenceName() != duplicateProperty.GetHiLoSequenceName() - || property.GetHiLoSequenceSchema() != duplicateProperty.GetHiLoSequenceSchema()) + if (property.GetHiLoSequenceName(storeObject) != duplicateProperty.GetHiLoSequenceName(storeObject) + || property.GetHiLoSequenceSchema(storeObject) != duplicateProperty.GetHiLoSequenceSchema(storeObject)) { throw new InvalidOperationException( SqlServerStrings.DuplicateColumnSequenceMismatch( diff --git a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerValueGeneratorCache.cs b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerValueGeneratorCache.cs index 1f13b0b0b23..fec6a2fa60f 100644 --- a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerValueGeneratorCache.cs +++ b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerValueGeneratorCache.cs @@ -48,7 +48,8 @@ public virtual SqlServerSequenceValueGeneratorState GetOrAddSequenceState( IProperty property, IRelationalConnection connection) { - var sequence = property.FindHiLoSequence(); + var sequence = property.FindHiLoSequence( + StoreObjectIdentifier.Create(property.DeclaringEntityType, StoreObjectType.Table).Value); Check.DebugAssert(sequence != null, "sequence is null"); diff --git a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs index da1b52beb30..f5ec8a9d6a2 100644 --- a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs +++ b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs @@ -11,7 +11,6 @@ using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.Logging; using Xunit; // ReSharper disable InconsistentNaming @@ -111,6 +110,17 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe modelBuilder.Model); } + [ConditionalFact] + public virtual void Passes_for_identity_seed_and_increment_on_owner() + { + var modelBuilder = CreateConventionalModelBuilder(); + modelBuilder.Entity().Property(a => a.Id).UseIdentityColumn(2, 3); + modelBuilder.Entity().OwnsOne(a => a.FavoritePerson); + modelBuilder.Entity(); + + Validate(modelBuilder.Model); + } + [ConditionalFact] public virtual void Passes_for_duplicate_column_names_with_HiLoSequence() {