diff --git a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs index 0d9f1a621ef..95fe56918d1 100644 --- a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs @@ -103,8 +103,12 @@ public virtual void ProcessModelFinalizing( foreach (var (conventionEntityType, exampleProperty) in entityTypesMissingConcurrencyColumn) { + var providerType = exampleProperty.GetProviderClrType() + ?? (exampleProperty.GetValueConverter() ?? + exampleProperty.FindTypeMapping()?.Converter)?.ProviderClrType + ?? exampleProperty.ClrType; conventionEntityType.Builder.CreateUniqueProperty( - exampleProperty.ClrType, + providerType, ConcurrencyPropertyPrefix + exampleProperty.Name, !exampleProperty.IsNullable)! .HasColumnName(concurrencyColumnName)! diff --git a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs index f3407b5bdc4..2d677e3f8a6 100644 --- a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs +++ b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs @@ -1713,7 +1713,7 @@ public virtual void Detects_missing_concurrency_token_on_the_sharing_type_withou } [ConditionalFact] - public virtual void Passes_with_missing_concurrency_token_property_on_the_base_type() + public virtual void Passes_for_missing_concurrency_token_property_on_the_base_type() { var modelBuilder = CreateConventionModelBuilder(); modelBuilder.Entity().ToTable(nameof(Animal)) @@ -1726,7 +1726,7 @@ public virtual void Passes_with_missing_concurrency_token_property_on_the_base_t } [ConditionalFact] - public virtual void Passes_with_missing_concurrency_token_property_on_the_base_type_when_derived_is_sharing() + public virtual void Passes_for_missing_concurrency_token_property_on_the_base_type_when_derived_is_sharing() { var modelBuilder = CreateConventionModelBuilder(); modelBuilder.Entity().ToTable(nameof(Animal)) @@ -1743,14 +1743,20 @@ public virtual void Passes_with_missing_concurrency_token_property_on_the_base_t } [ConditionalFact] - public virtual void Passes_with_missing_concurrency_token_property_on_the_sharing_type() + public virtual void Passes_for_missing_concurrency_token_property_on_the_sharing_type() { var modelBuilder = CreateConventionModelBuilder(); modelBuilder.Entity().ToTable(nameof(Animal)); modelBuilder.Entity().HasOne(a => a.FavoritePerson).WithOne().HasForeignKey(p => p.Id); - modelBuilder.Entity().Property("Version").IsRowVersion().HasColumnName("Version"); + modelBuilder.Entity().Property("Version") + .HasConversion().IsRowVersion(); - Validate(modelBuilder); + var model = Validate(modelBuilder); + + var personType = model.FindEntityType(typeof(Person))!; + var concurrencyProperty = personType.GetDeclaredProperties().Single(p => p.IsConcurrencyToken); + Assert.Equal("Version", concurrencyProperty.GetColumnName()); + Assert.Equal(typeof(byte[]), concurrencyProperty.ClrType); } [ConditionalFact] @@ -1777,9 +1783,17 @@ public virtual void Passes_for_missing_concurrency_token_on_owner() modelBuilder.Entity().OwnsOne( a => a.FavoritePerson, pb => pb.Property("Version").IsRowVersion().HasColumnName("Version")); - modelBuilder.Entity().Ignore(d => d.FavoritePerson); + modelBuilder.Entity().OwnsOne( + a => a.FavoritePerson); - Validate(modelBuilder); + var model = Validate(modelBuilder); + + var animalType = model.FindEntityType(typeof(Animal))!; + Assert.Null(animalType.GetDeclaredProperties().SingleOrDefault(p => p.IsConcurrencyToken)); + + var dogType = model.FindEntityType(typeof(Dog))!; + var concurrencyProperty = dogType.GetDeclaredProperties().Single(p => p.IsConcurrencyToken); + Assert.Equal("Version", concurrencyProperty.GetColumnName()); } [ConditionalFact] diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs index c07162a4ba7..b8329394064 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderTestBase.cs @@ -366,6 +366,7 @@ public virtual void TPC_identifying_FKs_are_created_on_all_tables() { b.ToTable("Ingredients"); b.Ignore(i => i.BigMak); + b.HasIndex(e => e.BurgerId); b.UseTpcMappingStrategy(); }); modelBuilder.Entity( @@ -388,10 +389,8 @@ public virtual void TPC_identifying_FKs_are_created_on_all_tables() Assert.Empty(principalType.GetIndexes()); Assert.Null(principalType.FindDiscriminatorProperty()); - var ingredientType = model.FindEntityType(typeof(Ingredient)); - var bunType = model.FindEntityType(typeof(Bun))!; - Assert.Empty(bunType.GetIndexes()); + Assert.Empty(bunType.GetDeclaredIndexes()); Assert.Null(bunType.FindDiscriminatorProperty()); var bunFk = bunType.GetDeclaredForeignKeys().Single(); Assert.Equal("FK_Buns_BigMak_Id", bunFk.GetConstraintName()); @@ -404,12 +403,20 @@ public virtual void TPC_identifying_FKs_are_created_on_all_tables() Assert.Empty(bunType.GetDeclaredForeignKeys().Where(fk => fk.IsBaseLinking())); var sesameBunType = model.FindEntityType(typeof(SesameBun))!; - Assert.Empty(sesameBunType.GetIndexes()); + Assert.Empty(sesameBunType.GetDeclaredIndexes()); Assert.Empty(sesameBunType.GetDeclaredForeignKeys()); Assert.Equal( "FK_SesameBuns_BigMak_Id", bunFk.GetConstraintName( StoreObjectIdentifier.Create(sesameBunType, StoreObjectType.Table)!.Value, StoreObjectIdentifier.Create(principalType, StoreObjectType.Table)!.Value)); + + var ingredientType = model.FindEntityType(typeof(Ingredient))!; + var ingredientIndex = ingredientType.GetDeclaredIndexes().Single(); + Assert.Equal("IX_Ingredients_BurgerId", ingredientIndex.GetDatabaseName()); + Assert.Equal("IX_SesameBuns_BurgerId", + ingredientIndex.GetDatabaseName(StoreObjectIdentifier.Create(sesameBunType, StoreObjectType.Table)!.Value)); + Assert.Equal("IX_Buns_BurgerId", + ingredientIndex.GetDatabaseName(StoreObjectIdentifier.Create(bunType, StoreObjectType.Table)!.Value)); } [ConditionalFact]