Skip to content

Commit badb28f

Browse files
authored
[release/8.0] Stop specifying incorrect column name in snapshot for owned type of generic entity type (#32963)
* Stop specifying incorrect column name in snapshot for owned type of generic entity type (#32937) Fixes #32763 * Add quirk and update baselines
1 parent c5d8f3c commit badb28f

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed

src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace Microsoft.EntityFrameworkCore;
1717
/// </remarks>
1818
public static class RelationalPropertyExtensions
1919
{
20+
private static readonly bool UseOldBehavior32763 =
21+
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32763", out var enabled32763) && enabled32763;
22+
2023
private static readonly MethodInfo GetFieldValueMethod =
2124
typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetFieldValue), new[] { typeof(int) })!;
2225

@@ -183,7 +186,10 @@ public static string GetDefaultColumnName(this IReadOnlyProperty property)
183186
var foreignKey = property.GetContainingForeignKeys().First();
184187
var principalEntityType = foreignKey.PrincipalEntityType;
185188
if (principalEntityType is { HasSharedClrType: false, ClrType.IsConstructedGenericType: true }
186-
&& foreignKey.DependentToPrincipal == null)
189+
&& foreignKey.DependentToPrincipal == null
190+
&& (UseOldBehavior32763
191+
|| principalEntityType.GetTableName() != foreignKey.DeclaringEntityType.GetTableName()
192+
|| principalEntityType.GetSchema() != foreignKey.DeclaringEntityType.GetSchema()))
187193
{
188194
var principalProperty = property.FindFirstPrincipal()!;
189195
var principalName = principalEntityType.ShortName();

test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,25 @@ public class FooExtension<T>
370370
public T Bar { get; set; }
371371
}
372372

373+
public class Parrot<TChild>
374+
{
375+
public int Id { get; set; }
376+
public string Name { get; set; }
377+
public TChild Child { get; set; }
378+
}
379+
380+
public class Parrot
381+
{
382+
public int Id { get; set; }
383+
public string Name { get; set; }
384+
public Beak Child { get; set; }
385+
}
386+
387+
public class Beak
388+
{
389+
public string Name { get; set; }
390+
}
391+
373392
#region Model
374393

375394
[ConditionalFact]
@@ -4648,6 +4667,139 @@ public virtual void Property_column_name_is_stored_in_snapshot_when_DefaultColum
46484667
var property = entityType.FindProperty("FooExtensionId");
46494668
Assert.NotNull(property);
46504669
Assert.Equal("FooExtension<BarA>Id", property.GetColumnName());
4670+
4671+
Assert.Collection(
4672+
model.GetRelationalModel().Tables,
4673+
t =>
4674+
{
4675+
4676+
Assert.Equal("BarBase", t.Name);
4677+
Assert.Equal(["Id", "Discriminator", "FooExtension<BarA>Id"], t.Columns.Select(t => t.Name));
4678+
},
4679+
t =>
4680+
{
4681+
4682+
Assert.Equal("FooExtension<BarA>", t.Name);
4683+
Assert.Equal(["Id"], t.Columns.Select(t => t.Name));
4684+
});
4685+
});
4686+
4687+
[ConditionalFact]
4688+
public virtual void Generic_entity_type_with_owned_entities()
4689+
=> Test(
4690+
modelBuilder => modelBuilder.Entity<Parrot<Beak>>().OwnsOne(e => e.Child),
4691+
AddBoilerPlate(
4692+
"""
4693+
modelBuilder
4694+
.HasDefaultSchema("DefaultSchema")
4695+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
4696+
4697+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
4698+
4699+
modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot<Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Beak>", b =>
4700+
{
4701+
b.Property<int>("Id")
4702+
.ValueGeneratedOnAdd()
4703+
.HasColumnType("int");
4704+
4705+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
4706+
4707+
b.Property<string>("Name")
4708+
.HasColumnType("nvarchar(max)");
4709+
4710+
b.HasKey("Id");
4711+
4712+
b.ToTable("Parrot<Beak>", "DefaultSchema");
4713+
});
4714+
4715+
modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot<Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Beak>", b =>
4716+
{
4717+
b.OwnsOne("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Beak", "Child", b1 =>
4718+
{
4719+
b1.Property<int>("ParrotId")
4720+
.HasColumnType("int");
4721+
4722+
b1.Property<string>("Name")
4723+
.HasColumnType("nvarchar(max)");
4724+
4725+
b1.HasKey("ParrotId");
4726+
4727+
b1.ToTable("Parrot<Beak>", "DefaultSchema");
4728+
4729+
b1.WithOwner()
4730+
.HasForeignKey("ParrotId");
4731+
});
4732+
4733+
b.Navigation("Child");
4734+
});
4735+
"""),
4736+
model =>
4737+
{
4738+
var parentType = model.FindEntityType("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot<Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Beak>");
4739+
Assert.NotNull(parentType);
4740+
Assert.NotNull(parentType.FindNavigation("Child")!.TargetEntityType);
4741+
4742+
var table = model.GetRelationalModel().Tables.Single();
4743+
Assert.Equal(["Id", "Child_Name", "Name"], table.Columns.Select(t => t.Name));
4744+
});
4745+
4746+
[ConditionalFact]
4747+
public virtual void Non_generic_entity_type_with_owned_entities()
4748+
=> Test(
4749+
modelBuilder => modelBuilder.Entity<Parrot>().OwnsOne(e => e.Child),
4750+
AddBoilerPlate(
4751+
"""
4752+
modelBuilder
4753+
.HasDefaultSchema("DefaultSchema")
4754+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
4755+
4756+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
4757+
4758+
modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot", b =>
4759+
{
4760+
b.Property<int>("Id")
4761+
.ValueGeneratedOnAdd()
4762+
.HasColumnType("int");
4763+
4764+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
4765+
4766+
b.Property<string>("Name")
4767+
.HasColumnType("nvarchar(max)");
4768+
4769+
b.HasKey("Id");
4770+
4771+
b.ToTable("Parrot", "DefaultSchema");
4772+
});
4773+
4774+
modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot", b =>
4775+
{
4776+
b.OwnsOne("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Beak", "Child", b1 =>
4777+
{
4778+
b1.Property<int>("ParrotId")
4779+
.HasColumnType("int");
4780+
4781+
b1.Property<string>("Name")
4782+
.HasColumnType("nvarchar(max)");
4783+
4784+
b1.HasKey("ParrotId");
4785+
4786+
b1.ToTable("Parrot", "DefaultSchema");
4787+
4788+
b1.WithOwner()
4789+
.HasForeignKey("ParrotId");
4790+
});
4791+
4792+
b.Navigation("Child");
4793+
});
4794+
"""),
4795+
model =>
4796+
{
4797+
var parentType = model.FindEntityType("Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+Parrot");
4798+
Assert.NotNull(parentType);
4799+
Assert.NotNull(parentType.FindNavigation("Child")!.TargetEntityType);
4800+
4801+
var table = model.GetRelationalModel().Tables.Single();
4802+
Assert.Equal(["Id", "Child_Name", "Name"], table.Columns.Select(t => t.Name));
46514803
});
46524804

46534805
[ConditionalFact]

0 commit comments

Comments
 (0)