From 8283aeecdfb61bf6feff46abf9d64e9f4b4eb8db Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Sat, 27 Jan 2024 10:30:20 +0000 Subject: [PATCH] Stop specifying incorrect column name in snapshot for owned type of generic entity type Fixes #32763 --- .../RelationalPropertyExtensions.cs | 4 +- ...rpMigrationsGeneratorTest.ModelSnapshot.cs | 152 ++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs index a0f4227b0ac..4f286884283 100644 --- a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs @@ -183,7 +183,9 @@ public static string GetDefaultColumnName(this IReadOnlyProperty property) var foreignKey = property.GetContainingForeignKeys().First(); var principalEntityType = foreignKey.PrincipalEntityType; if (principalEntityType is { HasSharedClrType: false, ClrType.IsConstructedGenericType: true } - && foreignKey.DependentToPrincipal == null) + && foreignKey.DependentToPrincipal == null + && (principalEntityType.GetTableName() != foreignKey.DeclaringEntityType.GetTableName() + || principalEntityType.GetSchema() != foreignKey.DeclaringEntityType.GetSchema())) { var principalProperty = property.FindFirstPrincipal()!; var principalName = principalEntityType.ShortName(); diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs index a2752cb916f..4748bd87906 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs @@ -608,6 +608,25 @@ public class FooExtension public T Bar { get; set; } } + public class Parrot + { + public int Id { get; set; } + public string Name { get; set; } + public TChild Child { get; set; } + } + + public class Parrot + { + public int Id { get; set; } + public string Name { get; set; } + public Beak Child { get; set; } + } + + public class Beak + { + public string Name { get; set; } + } + #region Model [ConditionalFact] @@ -4885,6 +4904,139 @@ public virtual void Property_column_name_is_stored_in_snapshot_when_DefaultColum var property = entityType.FindProperty("FooExtensionId"); Assert.NotNull(property); Assert.Equal("FooExtensionId", property.GetColumnName()); + + Assert.Collection( + model.GetRelationalModel().Tables, + t => + { + + Assert.Equal("BarBase", t.Name); + Assert.Equal(["Id", "Discriminator", "FooExtensionId"], t.Columns.Select(t => t.Name)); + }, + t => + { + + Assert.Equal("FooExtension", t.Name); + Assert.Equal(["Id"], t.Columns.Select(t => t.Name)); + }); + }); + + [ConditionalFact] + public virtual void Generic_entity_type_with_owned_entities() + => Test( + modelBuilder => modelBuilder.Entity>().OwnsOne(e => e.Child), + AddBoilerPlate( + """ + modelBuilder + .HasDefaultSchema("DefaultSchema") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Parrot", "DefaultSchema"); + }); + + modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot", b => + { + b.OwnsOne("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Beak", "Child", b1 => + { + b1.Property("ParrotId") + .HasColumnType("int"); + + b1.Property("Name") + .HasColumnType("nvarchar(max)"); + + b1.HasKey("ParrotId"); + + b1.ToTable("Parrot", "DefaultSchema"); + + b1.WithOwner() + .HasForeignKey("ParrotId"); + }); + + b.Navigation("Child"); + }); +"""), + model => + { + var parentType = model.FindEntityType("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot"); + Assert.NotNull(parentType); + Assert.NotNull(parentType.FindNavigation("Child")!.TargetEntityType); + + var table = model.GetRelationalModel().Tables.Single(); + Assert.Equal(["Id", "Child_Name", "Name"], table.Columns.Select(t => t.Name)); + }); + + [ConditionalFact] + public virtual void Non_generic_entity_type_with_owned_entities() + => Test( + modelBuilder => modelBuilder.Entity().OwnsOne(e => e.Child), + AddBoilerPlate( + """ + modelBuilder + .HasDefaultSchema("DefaultSchema") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Parrot", "DefaultSchema"); + }); + + modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot", b => + { + b.OwnsOne("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Beak", "Child", b1 => + { + b1.Property("ParrotId") + .HasColumnType("int"); + + b1.Property("Name") + .HasColumnType("nvarchar(max)"); + + b1.HasKey("ParrotId"); + + b1.ToTable("Parrot", "DefaultSchema"); + + b1.WithOwner() + .HasForeignKey("ParrotId"); + }); + + b.Navigation("Child"); + }); +"""), + model => + { + var parentType = model.FindEntityType("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+Parrot"); + Assert.NotNull(parentType); + Assert.NotNull(parentType.FindNavigation("Child")!.TargetEntityType); + + var table = model.GetRelationalModel().Tables.Single(); + Assert.Equal(["Id", "Child_Name", "Name"], table.Columns.Select(t => t.Name)); }); [ConditionalFact]