From 0cd5825bcd0e2593c1181f5fa2ee3d1c56501810 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 19 Nov 2021 13:55:23 +0100 Subject: [PATCH] Reset all primary keys in the TPT hierarchy Fixes #112 --- .../NameRewritingConventionTest.cs | 47 +++++++++++++++++-- .../Internal/NameRewritingConvention.cs | 19 ++++++-- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/EFCore.NamingConventions.Test/NameRewritingConventionTest.cs b/EFCore.NamingConventions.Test/NameRewritingConventionTest.cs index 39071c8..b77f13d 100644 --- a/EFCore.NamingConventions.Test/NameRewritingConventionTest.cs +++ b/EFCore.NamingConventions.Test/NameRewritingConventionTest.cs @@ -153,11 +153,50 @@ namespace EFCore.NamingConventions.Test Assert.Equal("child_property", childEntityType.FindProperty(nameof(Child.ChildProperty)) .GetColumnName(StoreObjectIdentifier.Create(childEntityType, StoreObjectType.Table)!.Value)); - var parentKey = parentEntityType.FindPrimaryKey(); - var childKey = childEntityType.FindPrimaryKey(); + var primaryKey = parentEntityType.FindPrimaryKey(); + Assert.Same(primaryKey, childEntityType.FindPrimaryKey()); - Assert.Equal("PK_parent", parentKey.GetName()); - Assert.Equal("PK_parent", childKey.GetName()); + Assert.Equal("PK_parent", primaryKey.GetName()); + + // For the following, see #112 + var parentStoreObjectIdentifier = StoreObjectIdentifier.Create(parentEntityType, StoreObjectType.Table).Value; + var childStoreObjectIdentifier = StoreObjectIdentifier.Create(childEntityType, StoreObjectType.Table).Value; + Assert.Equal("PK_parent", primaryKey.GetName(parentStoreObjectIdentifier)); + Assert.Equal("PK_child", primaryKey.GetName(childStoreObjectIdentifier)); + } + + [Fact] + public void TPT_reversed_configuration() + { + var model = BuildModel(b => + { + b.Entity().ToTable("child"); + b.Entity().ToTable("parent"); + }); + + var parentEntityType = model.FindEntityType(typeof(Parent)); + var childEntityType = model.FindEntityType(typeof(Child)); + + Assert.Equal("parent", parentEntityType.GetTableName()); + Assert.Equal("id", parentEntityType.FindProperty(nameof(Parent.Id)) + .GetColumnName(StoreObjectIdentifier.Create(parentEntityType, StoreObjectType.Table)!.Value)); + Assert.Equal("parent_property", parentEntityType.FindProperty(nameof(Parent.ParentProperty)) + .GetColumnName(StoreObjectIdentifier.Create(parentEntityType, StoreObjectType.Table)!.Value)); + + Assert.Equal("child", childEntityType.GetTableName()); + Assert.Equal("child_property", childEntityType.FindProperty(nameof(Child.ChildProperty)) + .GetColumnName(StoreObjectIdentifier.Create(childEntityType, StoreObjectType.Table)!.Value)); + + var primaryKey = parentEntityType.FindPrimaryKey(); + Assert.Same(primaryKey, childEntityType.FindPrimaryKey()); + + Assert.Equal("PK_parent", primaryKey.GetName()); + + // For the following, see #112 + var parentStoreObjectIdentifier = StoreObjectIdentifier.Create(parentEntityType, StoreObjectType.Table).Value; + var childStoreObjectIdentifier = StoreObjectIdentifier.Create(childEntityType, StoreObjectType.Table).Value; + Assert.Equal("PK_parent", primaryKey.GetName(parentStoreObjectIdentifier)); + Assert.Equal("PK_child", primaryKey.GetName(childStoreObjectIdentifier)); } [Fact] diff --git a/EFCore.NamingConventions/Internal/NameRewritingConvention.cs b/EFCore.NamingConventions/Internal/NameRewritingConvention.cs index 113d8db..9f502d3 100644 --- a/EFCore.NamingConventions/Internal/NameRewritingConvention.cs +++ b/EFCore.NamingConventions/Internal/NameRewritingConvention.cs @@ -136,14 +136,27 @@ namespace EFCore.NamingConventions.Internal // However, this isn't yet supported with TPT, see https://github.com/dotnet/efcore/issues/23444. // So we need to check if the entity is within a TPT hierarchy, or is an owned entity within a TPT hierarchy. - if (entityType.FindRowInternalForeignKeys(tableIdentifier).FirstOrDefault() is null - && (entityType.BaseType is null || entityType.GetTableName() == entityType.BaseType.GetTableName())) + var rootType = entityType.GetRootType(); + var isTPT = rootType.GetDerivedTypes().FirstOrDefault() is { } derivedType + && derivedType.GetTableName() != rootType.GetTableName(); + + if (entityType.FindRowInternalForeignKeys(tableIdentifier).FirstOrDefault() is null && !isTPT) { primaryKey.Builder.HasName(_namingNameRewriter.RewriteName(primaryKey.GetDefaultName())); } else { - primaryKey.Builder.HasNoAnnotation(RelationalAnnotationNames.Name); + // This hierarchy is being transformed into TPT via the explicit setting of the table name. + // We not only have to reset our own key name, but also the parents'. Otherwise, the parent's key name + // is used as the child's (see RelationalKeyExtensions.GetName), and we get a "duplicate key name in database" error + // since both parent and child have the same key name; + foreach (var type in entityType.GetRootType().GetDerivedTypesInclusive()) + { + if (type.FindPrimaryKey() is IConventionKey pk) + { + pk.Builder.HasNoAnnotation(RelationalAnnotationNames.Name); + } + } } }