From 9949876afdcc6a95a239199b3fc1e49d422e82f9 Mon Sep 17 00:00:00 2001 From: lajones Date: Tue, 8 Dec 2015 16:18:30 -0800 Subject: [PATCH] Don't produce HasIndex() API if it would already be assumed due to it supporting a primary key, but make allowance for the outputting HasName() (on a primary key) or HasConstraintName() (on a foreign key) as needed. --- .../KeyFluentApiConfiguration.cs | 37 ++++++++++----- .../Configuration/ModelConfiguration.cs | 22 ++++----- .../Internal/ConfigurationFactory.cs | 6 +-- .../Internal/ScaffoldingUtilities.cs | 47 ++++++++++++++----- .../SqlServerDesignStrings.Designer.cs | 8 ++++ .../Properties/SqlServerDesignStrings.resx | 3 ++ .../SqlServerDatabaseModelFactory.cs | 3 +- .../RelationalScaffoldingModelFactory.cs | 37 +++++++++++++-- .../RelationalForeignKeyAnnotations.cs | 20 ++++++-- .../Metadata/RelationalKeyAnnotations.cs | 20 ++++++-- .../ReverseEngineering/E2E.sql | 14 +++--- ...rverReverseEngineerTestE2EContext.expected | 39 ++++++++++----- .../AttributesContext.expected | 27 +++++++---- .../SqlServerDatabaseModelFactoryTest.cs | 7 +++ .../OneToManyFluentApiContext.expected | 6 ++- .../OneToManyAttributesContext.expected | 6 ++- 16 files changed, 217 insertions(+), 85 deletions(-) diff --git a/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/KeyFluentApiConfiguration.cs b/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/KeyFluentApiConfiguration.cs index ec9389c3014..017d140ce56 100644 --- a/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/KeyFluentApiConfiguration.cs +++ b/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/KeyFluentApiConfiguration.cs @@ -14,27 +14,40 @@ public class KeyFluentApiConfiguration : IFluentApiConfiguration { public KeyFluentApiConfiguration( [NotNull] string lambdaIdentifier, - [NotNull] IReadOnlyList properties) + [NotNull] Key key) { Check.NotEmpty(lambdaIdentifier, nameof(lambdaIdentifier)); - Check.NotEmpty(properties, nameof(properties)); + Check.NotNull(key, nameof(key)); LambdaIdentifier = lambdaIdentifier; - Properties = new List(properties); + Key = key; } public virtual string LambdaIdentifier { get; } - public virtual IReadOnlyList Properties { get; } + public virtual Key Key { get; } public virtual bool HasAttributeEquivalent { get; set; } - public virtual ICollection FluentApiLines => - new List { string.Format( - CultureInfo.InvariantCulture, - "{0}({1} => {2})", - nameof(EntityTypeBuilder.HasKey), - LambdaIdentifier, - new ScaffoldingUtilities().GenerateLambdaToKey(Properties, LambdaIdentifier)) - }; + public virtual ICollection FluentApiLines + { + get + { + var lines = new List(); + lines.Add(string.Format( + CultureInfo.InvariantCulture, + "{0}({1} => {2})", + nameof(EntityTypeBuilder.HasKey), + LambdaIdentifier, + new ScaffoldingUtilities().GenerateLambdaToKey(Key.Properties, LambdaIdentifier))); + + if (Key.Relational().Name != null) + { + lines.Add("." + nameof(RelationalKeyBuilderExtensions.HasName) + + "(" + CSharpUtilities.Instance.DelimitString(Key.Relational().Name) + ")"); + } + + return lines; + } + } } } diff --git a/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/ModelConfiguration.cs b/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/ModelConfiguration.cs index 65603d1e3d8..6f5ad3a9203 100644 --- a/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/ModelConfiguration.cs +++ b/src/EntityFramework.Commands/Scaffolding/Internal/Configuration/ModelConfiguration.cs @@ -179,9 +179,15 @@ public virtual void AddKeyConfiguration([NotNull] EntityConfiguration entityConf if (key.IsPrimaryKey()) { var keyFluentApi = _configurationFactory - .CreateKeyFluentApiConfiguration("e", key.Properties); - - if (key.Properties.Count == 1) + .CreateKeyFluentApiConfiguration("e", key); + + if (key.Properties.Count == 1 + && key.Relational().Name == + RelationalKeyAnnotations + .GetDefaultKeyName( + entityType.Relational().TableName, + true, /* is primary key */ + key.Properties.Select(p => p.Name))) { keyFluentApi.HasAttributeEquivalent = true; @@ -241,15 +247,9 @@ public virtual void AddIndexConfigurations([NotNull] EntityConfiguration entityC { Check.NotNull(entityConfiguration, nameof(entityConfiguration)); - var entityType = (EntityType)entityConfiguration.EntityType; - var primaryKeyProperties = entityType.FindPrimaryKey()?.Properties; - foreach (var index in entityType.GetIndexes()) + foreach (var index in entityConfiguration.EntityType.GetIndexes().Cast()) { - // do not add indexes for the primary key - if (!index.Properties.SequenceEqual(primaryKeyProperties)) - { - AddIndexConfiguration(entityConfiguration, index); - } + AddIndexConfiguration(entityConfiguration, index); } } diff --git a/src/EntityFramework.Commands/Scaffolding/Internal/ConfigurationFactory.cs b/src/EntityFramework.Commands/Scaffolding/Internal/ConfigurationFactory.cs index c91d5cbad2f..d6943ad9560 100644 --- a/src/EntityFramework.Commands/Scaffolding/Internal/ConfigurationFactory.cs +++ b/src/EntityFramework.Commands/Scaffolding/Internal/ConfigurationFactory.cs @@ -124,12 +124,12 @@ public virtual FluentApiConfiguration CreateFluentApiConfiguration( public virtual KeyFluentApiConfiguration CreateKeyFluentApiConfiguration( [NotNull] string lambdaIdentifier, - [NotNull] IReadOnlyList properties) + [NotNull] Key key) { Check.NotEmpty(lambdaIdentifier, nameof(lambdaIdentifier)); - Check.NotEmpty(properties, nameof(properties)); + Check.NotNull(key, nameof(key)); - return new KeyFluentApiConfiguration(lambdaIdentifier, properties); + return new KeyFluentApiConfiguration(lambdaIdentifier, key); } public virtual AttributeConfiguration CreateAttributeConfiguration( diff --git a/src/EntityFramework.Commands/Scaffolding/Internal/ScaffoldingUtilities.cs b/src/EntityFramework.Commands/Scaffolding/Internal/ScaffoldingUtilities.cs index 593a1edf6b5..2a38acf7008 100644 --- a/src/EntityFramework.Commands/Scaffolding/Internal/ScaffoldingUtilities.cs +++ b/src/EntityFramework.Commands/Scaffolding/Internal/ScaffoldingUtilities.cs @@ -7,6 +7,7 @@ using JetBrains.Annotations; using Microsoft.Data.Entity.Internal; using Microsoft.Data.Entity.Metadata; +using Microsoft.Data.Entity.Metadata.Builders; using Microsoft.Data.Entity.Metadata.Internal; using Microsoft.Data.Entity.Scaffolding.Internal.Configuration; using Microsoft.Data.Entity.Utilities; @@ -52,7 +53,7 @@ public virtual void LayoutRelationshipConfigurationLines( Check.NotEmpty(principalEndLambdaIdentifier, nameof(principalEndLambdaIdentifier)); sb.Append(entityLambdaIdentifier); - sb.Append(".HasOne("); + sb.Append("." + nameof(EntityTypeBuilder.HasOne) + "("); sb.Append(dependentEndLambdaIdentifier); sb.Append(" => "); sb.Append(dependentEndLambdaIdentifier); @@ -62,14 +63,10 @@ public virtual void LayoutRelationshipConfigurationLines( using (sb.Indent()) { - if (rc.ForeignKey.IsUnique) - { - sb.Append(".WithOne("); - } - else - { - sb.Append(".WithMany("); - } + var withMethodName = rc.ForeignKey.IsUnique + ? nameof(ReferenceNavigationBuilder.WithOne) + : nameof(ReferenceNavigationBuilder.WithMany); + sb.Append("." + withMethodName + "("); if (!string.IsNullOrEmpty(rc.PrincipalEndNavigationPropertyName)) { sb.Append(principalEndLambdaIdentifier); @@ -82,7 +79,10 @@ public virtual void LayoutRelationshipConfigurationLines( if (!rc.ForeignKey.PrincipalKey.IsPrimaryKey()) { - sb.Append(".HasPrincipalKey"); + var hasPrincipalKeyMethodName = rc.ForeignKey.IsUnique + ? nameof(ReferenceReferenceBuilder.HasPrincipalKey) + : nameof(ReferenceReferenceBuilder.HasPrincipalKey); + sb.Append("." + hasPrincipalKeyMethodName); if (rc.ForeignKey.IsUnique) { // If the relationship is 1:1 need to define to which end @@ -98,7 +98,10 @@ public virtual void LayoutRelationshipConfigurationLines( .AppendLine(")"); } - sb.Append(".HasForeignKey"); + var hasForeignKeyMethodName = rc.ForeignKey.IsUnique + ? nameof(ReferenceReferenceBuilder.HasForeignKey) + : nameof(ReferenceCollectionBuilder.HasForeignKey); + sb.Append("." + hasForeignKeyMethodName); if (rc.ForeignKey.IsUnique) { // If the relationship is 1:1 need to define to which end @@ -121,11 +124,31 @@ public virtual void LayoutRelationshipConfigurationLines( if (rc.OnDeleteAction != defaultOnDeleteAction) { sb.AppendLine(); - sb.Append(".OnDelete("); + var onDeleteMethodName = rc.ForeignKey.IsUnique + ? nameof(ReferenceReferenceBuilder.OnDelete) + : nameof(ReferenceCollectionBuilder.OnDelete); + sb.Append("." + onDeleteMethodName + "("); sb.Append(CSharpUtilities.Instance.GenerateLiteral(rc.OnDeleteAction)); sb.Append(")"); } + var foreignKey = rc.ForeignKey as ForeignKey; + if (foreignKey != null + && foreignKey.Relational().Name != + RelationalForeignKeyAnnotations.GetDefaultForeignKeyName( + foreignKey.DeclaringEntityType.Relational().TableName, + foreignKey.PrincipalEntityType.Relational().TableName, + foreignKey.Properties.Select(p => p.Name))) + { + sb.AppendLine(); + var hasConstraintMethodName = foreignKey.IsUnique + ? nameof(RelationalReferenceReferenceBuilderExtensions.HasConstraintName) + : nameof(RelationalReferenceCollectionBuilderExtensions.HasConstraintName); + sb.Append("." + hasConstraintMethodName + "("); + sb.Append(CSharpUtilities.Instance.DelimitString(foreignKey.Relational().Name)); + sb.Append(")"); + } + sb.AppendLine(";"); } } diff --git a/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.Designer.cs b/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.Designer.cs index e8a39009457..3a5411051e5 100644 --- a/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.Designer.cs +++ b/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.Designer.cs @@ -52,6 +52,14 @@ public static string DataTypeDoesNotAllowSqlServerIdentityStrategy([CanBeNull] o return string.Format(CultureInfo.CurrentCulture, GetString("DataTypeDoesNotAllowSqlServerIdentityStrategy", "columnId", "sqlServerDataType"), columnId, sqlServerDataType); } + /// + /// Found a foreign key on table [{schemaName}].[{tableName}] with an empty or null name. Skipping foreign key. + /// + public static string ForeignKeyNameEmpty([CanBeNull] object schemaName, [CanBeNull] object tableName) + { + return string.Format(CultureInfo.CurrentCulture, GetString("ForeignKeyNameEmpty", "schemaName", "tableName"), schemaName, tableName); + } + /// /// Found an index on table [{schemaName}].[{tableName}] with an empty or null name. Skipping index. /// diff --git a/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.resx b/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.resx index 9efa40c704b..a2287880e11 100644 --- a/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.resx +++ b/src/EntityFramework.MicrosoftSqlServer.Design/Properties/SqlServerDesignStrings.resx @@ -132,6 +132,9 @@ For column {columnId}. This column is set up as an Identity column, but the SQL Server data type is {sqlServerDataType}. This will be mapped to CLR type byte which does not allow the SqlServerValueGenerationStrategy.IdentityColumn setting. Generating a matching Property but ignoring the Identity setting. + + Found a foreign key on table [{schemaName}].[{tableName}] with an empty or null name. Skipping foreign key. + Found an index on table [{schemaName}].[{tableName}] with an empty or null name. Skipping index. diff --git a/src/EntityFramework.MicrosoftSqlServer.Design/SqlServerDatabaseModelFactory.cs b/src/EntityFramework.MicrosoftSqlServer.Design/SqlServerDatabaseModelFactory.cs index 7c7a6c97306..6d5651103fb 100644 --- a/src/EntityFramework.MicrosoftSqlServer.Design/SqlServerDatabaseModelFactory.cs +++ b/src/EntityFramework.MicrosoftSqlServer.Design/SqlServerDatabaseModelFactory.cs @@ -223,7 +223,6 @@ FROM sys.indexes i INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id INNER JOIN sys.columns c ON ic.object_id = c.object_id AND c.column_id = ic.column_id WHERE object_schema_name(i.object_id) <> 'sys' - AND i.is_primary_key <> 1 AND object_name(i.object_id) <> '" + HistoryRepository.DefaultTableName + @"' ORDER BY object_schema_name(i.object_id), object_name(i.object_id), i.name, ic.key_ordinal"; @@ -321,6 +320,7 @@ FROM sys.foreign_keys AS f var fkName = reader.GetStringOrNull(2); if (string.IsNullOrEmpty(fkName)) { + Logger.LogWarning(SqlServerDesignStrings.ForeignKeyNameEmpty(schemaName, tableName)); continue; } @@ -349,6 +349,7 @@ FROM sys.foreign_keys AS f fkInfo = new ForeignKeyModel { + Name = fkName, Table = table, PrincipalTable = principalTable }; diff --git a/src/EntityFramework.Relational.Design/RelationalScaffoldingModelFactory.cs b/src/EntityFramework.Relational.Design/RelationalScaffoldingModelFactory.cs index abd356cc872..31febb55f27 100644 --- a/src/EntityFramework.Relational.Design/RelationalScaffoldingModelFactory.cs +++ b/src/EntityFramework.Relational.Design/RelationalScaffoldingModelFactory.cs @@ -236,7 +236,7 @@ protected virtual KeyBuilder VisitPrimaryKey([NotNull] EntityTypeBuilder builder .Where(c => c.PrimaryKeyOrdinal.HasValue) .OrderBy(c => c.PrimaryKeyOrdinal) .ToList(); - + if (keyColumns.Count == 0) { Logger.LogWarning(RelationalDesignStrings.MissingPrimaryKey(table.DisplayName)); @@ -274,15 +274,40 @@ protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [ Check.NotNull(builder, nameof(builder)); Check.NotNull(index, nameof(index)); - var properties = index.Columns.Select(GetPropertyName).ToArray(); + var propertyNames = index.Columns.Select(GetPropertyName).ToArray(); - if (properties.Count(p => builder.Metadata.FindProperty(p) != null) != properties.Length) + if (propertyNames.Count(p => builder.Metadata.FindProperty(p) != null) != propertyNames.Length) { Logger.LogWarning(RelationalDesignStrings.UnableToScaffoldIndexMissingProperty(index.Name)); return null; } - var indexBuilder = builder.HasIndex(properties) + var columnNames = index.Columns.Select(c => c.Name); + if (index.Table != null) + { + var primaryKeyColumns = index.Table.Columns + .Where(c => c.PrimaryKeyOrdinal.HasValue) + .OrderBy(c => c.PrimaryKeyOrdinal); + if (columnNames.SequenceEqual(primaryKeyColumns.Select(c => c.Name))) + { + // index is supporting the primary key. So there is no need for + // an extra index in the model. But if the index name does not + // match what would be produced by default then need to call + // HasName() on the primary key. + if (index.Name != + RelationalKeyAnnotations + .GetDefaultKeyName( + index.Table.Name, + true, /* is primary key */ + primaryKeyColumns.Select(c => GetPropertyName(c)))) + { + builder.HasKey(propertyNames.ToArray()).HasName(index.Name); + } + return null; + } + } + + var indexBuilder = builder.HasIndex(propertyNames) .IsUnique(index.IsUnique); if (!string.IsNullOrEmpty(index.Name)) @@ -292,7 +317,7 @@ protected virtual IndexBuilder VisitIndex([NotNull] EntityTypeBuilder builder, [ if (index.IsUnique) { - var keyBuilder = builder.HasAlternateKey(properties); + var keyBuilder = builder.HasAlternateKey(propertyNames); if (!string.IsNullOrEmpty(index.Name)) { keyBuilder.HasName(index.Name); @@ -389,6 +414,8 @@ protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder mode key.IsUnique = dependentEntityType.FindKey(depProps) != null; + key.Relational().Name = foreignKey.Name; + AssignOnDeleteAction(foreignKey, key); return key; diff --git a/src/EntityFramework.Relational/Metadata/RelationalForeignKeyAnnotations.cs b/src/EntityFramework.Relational/Metadata/RelationalForeignKeyAnnotations.cs index ae88ba2ef59..ab5aed3a57c 100644 --- a/src/EntityFramework.Relational/Metadata/RelationalForeignKeyAnnotations.cs +++ b/src/EntityFramework.Relational/Metadata/RelationalForeignKeyAnnotations.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Microsoft.Data.Entity.Metadata.Internal; @@ -40,9 +41,22 @@ protected virtual string GetDefaultName() ForeignKey.PrincipalEntityType, Annotations.ProviderPrefix); - return "FK_" + entityType.TableName + - "_" + principalEntityType.TableName + - "_" + string.Join("_", ForeignKey.Properties.Select(p => p.Name)); + return GetDefaultForeignKeyName(entityType.TableName, + principalEntityType.TableName, ForeignKey.Properties.Select(p => p.Name)); + } + + public static string GetDefaultForeignKeyName( + [NotNull] string dependentTableName, + [NotNull] string principalTableName, + [NotNull] IEnumerable dependentEndPropertyNames) + { + Check.NotEmpty(dependentTableName, nameof(dependentTableName)); + Check.NotEmpty(principalTableName, nameof(principalTableName)); + Check.NotNull(dependentEndPropertyNames, nameof(dependentEndPropertyNames)); + + return "FK_" + dependentTableName + + "_" + principalTableName + + "_" + string.Join("_", dependentEndPropertyNames); } } } diff --git a/src/EntityFramework.Relational/Metadata/RelationalKeyAnnotations.cs b/src/EntityFramework.Relational/Metadata/RelationalKeyAnnotations.cs index 1c05da3a041..94e869b16b3 100644 --- a/src/EntityFramework.Relational/Metadata/RelationalKeyAnnotations.cs +++ b/src/EntityFramework.Relational/Metadata/RelationalKeyAnnotations.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; using System.Linq; using System.Text; using JetBrains.Annotations; @@ -36,18 +37,27 @@ protected virtual bool SetName([CanBeNull] string value) protected virtual string GetDefaultName() { - var builder = new StringBuilder(); var entityType = new RelationalEntityTypeAnnotations(Key.DeclaringEntityType, Annotations.ProviderPrefix); + return GetDefaultKeyName(entityType.TableName, Key.IsPrimaryKey(), Key.Properties.Select(p => p.Name)); + } + + public static string GetDefaultKeyName( + [NotNull] string tableName, bool primaryKey, [NotNull] IEnumerable propertyNames) + { + Check.NotEmpty(tableName, nameof(tableName)); + Check.NotNull(propertyNames, nameof(propertyNames)); + + var builder = new StringBuilder(); builder - .Append(Key.IsPrimaryKey() ? "PK_" : "AK_") - .Append(entityType.TableName); + .Append(primaryKey ? "PK_" : "AK_") + .Append(tableName); - if (!Key.IsPrimaryKey()) + if (!primaryKey) { builder .Append("_") - .Append(string.Join("_", Key.Properties.Select(p => p.Name))); + .Append(string.Join("_", propertyNames)); } return builder.ToString(); diff --git a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/E2E.sql b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/E2E.sql index de8ffc8371b..9d039931fc0 100644 --- a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/E2E.sql +++ b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/E2E.sql @@ -202,7 +202,7 @@ CREATE TABLE "OneToManyPrincipal" ( "OneToManyPrincipalID1" "int", "OneToManyPrincipalID2" "int", "Other" nvarchar(20) NOT NULL, - CONSTRAINT "PK_OneToManyPrincipal" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToManyPrincipal" PRIMARY KEY CLUSTERED ( "OneToManyPrincipalID1", "OneToManyPrincipalID2" ) @@ -216,7 +216,7 @@ CREATE TABLE "OneToManyDependent" ( "SomeDependentEndColumn" nvarchar (20) NOT NULL, "OneToManyDependentFK2" "int" NULL, -- deliberately put FK columns in other order to make sure we get correct order in key "OneToManyDependentFK1" "int" NULL, - CONSTRAINT "PK_OneToManyDependent" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToManyDependent" PRIMARY KEY CLUSTERED ( "OneToManyDependentID1", "OneToManyDependentID2" ), @@ -234,7 +234,7 @@ CREATE TABLE "OneToOnePrincipal" ( "OneToOnePrincipalID1" "int", "OneToOnePrincipalID2" "int", "SomeOneToOnePrincipalColumn" nvarchar (20) NOT NULL, - CONSTRAINT "PK_OneToOnePrincipal" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToOnePrincipal" PRIMARY KEY CLUSTERED ( "OneToOnePrincipalID1", "OneToOnePrincipalID2" ) @@ -246,7 +246,7 @@ CREATE TABLE "OneToOneDependent" ( "OneToOneDependentID1" "int", "OneToOneDependentID2" "int", "SomeDependentEndColumn" nvarchar (20) NOT NULL, - CONSTRAINT "PK_OneToOneDependent" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToOneDependent" PRIMARY KEY CLUSTERED ( "OneToOneDependentID1", "OneToOneDependentID2" ), @@ -264,7 +264,7 @@ CREATE TABLE "OneToOneSeparateFKPrincipal" ( "OneToOneSeparateFKPrincipalID1" "int", "OneToOneSeparateFKPrincipalID2" "int", "SomeOneToOneSeparateFKPrincipalColumn" nvarchar (20) NOT NULL, - CONSTRAINT "PK_OneToOneSeparateFKPrincipal" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToOneSeparateFKPrincipal" PRIMARY KEY CLUSTERED ( "OneToOneSeparateFKPrincipalID1", "OneToOneSeparateFKPrincipalID2" ) @@ -278,7 +278,7 @@ CREATE TABLE "OneToOneSeparateFKDependent" ( "SomeDependentEndColumn" nvarchar (20) NOT NULL, "OneToOneSeparateFKDependentFK1" "int" NULL, "OneToOneSeparateFKDependentFK2" "int" NULL, - CONSTRAINT "PK_OneToOneSeparateFKDependent" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToOneSeparateFKDependent" PRIMARY KEY CLUSTERED ( "OneToOneSeparateFKDependentID1", "OneToOneSeparateFKDependentID2" ), @@ -320,7 +320,7 @@ CREATE TABLE "OneToOneFKToUniqueKeyDependent" ( "SomeColumn" nvarchar (20) NOT NULL, "OneToOneFKToUniqueKeyDependentFK1" "int" NULL, "OneToOneFKToUniqueKeyDependentFK2" "int" NULL, - CONSTRAINT "PK_OneToOneFKToUniqueKeyDependent" PRIMARY KEY CLUSTERED + CONSTRAINT "PK_OneToOneFKToUniqueKeyDependent" PRIMARY KEY CLUSTERED ( "OneToOneFKToUniqueKeyDependentID1", "OneToOneFKToUniqueKeyDependentID2" ), diff --git a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_AllFluentApi/SqlServerReverseEngineerTestE2EContext.expected b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_AllFluentApi/SqlServerReverseEngineerTestE2EContext.expected index 918d1e5a324..12aff21c9ab 100644 --- a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_AllFluentApi/SqlServerReverseEngineerTestE2EContext.expected +++ b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_AllFluentApi/SqlServerReverseEngineerTestE2EContext.expected @@ -69,7 +69,8 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }); + entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }) + .HasName("PK_OneToManyDependent"); entity.Property(e => e.SomeDependentEndColumn) .IsRequired() @@ -77,12 +78,14 @@ namespace E2ETest.Namespace entity.HasOne(d => d.OneToManyDependentFK) .WithMany(p => p.OneToManyDependent) - .HasForeignKey(d => new { d.OneToManyDependentFK1, d.OneToManyDependentFK2 }); + .HasForeignKey(d => new { d.OneToManyDependentFK1, d.OneToManyDependentFK2 }) + .HasConstraintName("FK_OneToManyDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }); + entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }) + .HasName("PK_OneToManyPrincipal"); entity.Property(e => e.Other) .IsRequired() @@ -91,7 +94,8 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneDependentID1, e.OneToOneDependentID2 }); + entity.HasKey(e => new { e.OneToOneDependentID1, e.OneToOneDependentID2 }) + .HasName("PK_OneToOneDependent"); entity.Property(e => e.SomeDependentEndColumn) .IsRequired() @@ -100,12 +104,14 @@ namespace E2ETest.Namespace entity.HasOne(d => d.OneToOneDependentNavigation) .WithOne(p => p.OneToOneDependent) .HasForeignKey(d => new { d.OneToOneDependentID1, d.OneToOneDependentID2 }) - .OnDelete(DeleteBehavior.Restrict); + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("FK_OneToOneDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneFKToUniqueKeyDependentID1, e.OneToOneFKToUniqueKeyDependentID2 }); + entity.HasKey(e => new { e.OneToOneFKToUniqueKeyDependentID1, e.OneToOneFKToUniqueKeyDependentID2 }) + .HasName("PK_OneToOneFKToUniqueKeyDependent"); entity.HasIndex(e => new { e.OneToOneFKToUniqueKeyDependentFK1, e.OneToOneFKToUniqueKeyDependentFK2 }) .HasName("UK_OneToOneFKToUniqueKeyDependent") @@ -118,12 +124,14 @@ namespace E2ETest.Namespace entity.HasOne(d => d.OneToOneFKToUniqueKeyDependentFK) .WithOne(p => p.OneToOneFKToUniqueKeyDependent) .HasPrincipalKey(p => new { p.OneToOneFKToUniqueKeyPrincipalUniqueKey1, p.OneToOneFKToUniqueKeyPrincipalUniqueKey2 }) - .HasForeignKey(d => new { d.OneToOneFKToUniqueKeyDependentFK1, d.OneToOneFKToUniqueKeyDependentFK2 }); + .HasForeignKey(d => new { d.OneToOneFKToUniqueKeyDependentFK1, d.OneToOneFKToUniqueKeyDependentFK2 }) + .HasConstraintName("FK_OneToOneFKToUniqueKeyDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneFKToUniqueKeyPrincipalID1, e.OneToOneFKToUniqueKeyPrincipalID2 }); + entity.HasKey(e => new { e.OneToOneFKToUniqueKeyPrincipalID1, e.OneToOneFKToUniqueKeyPrincipalID2 }) + .HasName("PK_OneToOneFKToUniqueKeyPrincipal"); entity.HasIndex(e => new { e.OneToOneFKToUniqueKeyPrincipalUniqueKey1, e.OneToOneFKToUniqueKeyPrincipalUniqueKey2 }) .HasName("UK_OneToOneFKToUniqueKeyPrincipal") @@ -136,7 +144,8 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOnePrincipalID1, e.OneToOnePrincipalID2 }); + entity.HasKey(e => new { e.OneToOnePrincipalID1, e.OneToOnePrincipalID2 }) + .HasName("PK_OneToOnePrincipal"); entity.Property(e => e.SomeOneToOnePrincipalColumn) .IsRequired() @@ -145,7 +154,8 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneSeparateFKDependentID1, e.OneToOneSeparateFKDependentID2 }); + entity.HasKey(e => new { e.OneToOneSeparateFKDependentID1, e.OneToOneSeparateFKDependentID2 }) + .HasName("PK_OneToOneSeparateFKDependent"); entity.HasIndex(e => new { e.OneToOneSeparateFKDependentFK1, e.OneToOneSeparateFKDependentFK2 }) .HasName("UK_OneToOneSeparateFKDependent") @@ -157,12 +167,14 @@ namespace E2ETest.Namespace entity.HasOne(d => d.OneToOneSeparateFKDependentFK) .WithOne(p => p.OneToOneSeparateFKDependent) - .HasForeignKey(d => new { d.OneToOneSeparateFKDependentFK1, d.OneToOneSeparateFKDependentFK2 }); + .HasForeignKey(d => new { d.OneToOneSeparateFKDependentFK1, d.OneToOneSeparateFKDependentFK2 }) + .HasConstraintName("FK_OneToOneSeparateFKDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneSeparateFKPrincipalID1, e.OneToOneSeparateFKPrincipalID2 }); + entity.HasKey(e => new { e.OneToOneSeparateFKPrincipalID1, e.OneToOneSeparateFKPrincipalID2 }) + .HasName("PK_OneToOneSeparateFKPrincipal"); entity.Property(e => e.SomeOneToOneSeparateFKPrincipalColumn) .IsRequired() @@ -225,7 +237,8 @@ namespace E2ETest.Namespace entity.HasOne(d => d.SelfReferenceFKNavigation) .WithMany(p => p.InverseSelfReferenceFKNavigation) - .HasForeignKey(d => d.SelfReferenceFK); + .HasForeignKey(d => d.SelfReferenceFK) + .HasConstraintName("FK_SelfReferencing"); }); modelBuilder.Entity(entity => diff --git a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_UseAttributesInsteadOfFluentApi/AttributesContext.expected b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_UseAttributesInsteadOfFluentApi/AttributesContext.expected index 439a75fedd4..414deadfafe 100644 --- a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_UseAttributesInsteadOfFluentApi/AttributesContext.expected +++ b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/ReverseEngineering/ExpectedResults/E2E_UseAttributesInsteadOfFluentApi/AttributesContext.expected @@ -57,22 +57,26 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }); + entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }) + .HasName("PK_OneToManyDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }); + entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }) + .HasName("PK_OneToManyPrincipal"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneDependentID1, e.OneToOneDependentID2 }); + entity.HasKey(e => new { e.OneToOneDependentID1, e.OneToOneDependentID2 }) + .HasName("PK_OneToOneDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneFKToUniqueKeyDependentID1, e.OneToOneFKToUniqueKeyDependentID2 }); + entity.HasKey(e => new { e.OneToOneFKToUniqueKeyDependentID1, e.OneToOneFKToUniqueKeyDependentID2 }) + .HasName("PK_OneToOneFKToUniqueKeyDependent"); entity.HasIndex(e => new { e.OneToOneFKToUniqueKeyDependentFK1, e.OneToOneFKToUniqueKeyDependentFK2 }) .HasName("UK_OneToOneFKToUniqueKeyDependent") @@ -81,12 +85,14 @@ namespace E2ETest.Namespace entity.HasOne(d => d.OneToOneFKToUniqueKeyDependentFK) .WithOne(p => p.OneToOneFKToUniqueKeyDependent) .HasPrincipalKey(p => new { p.OneToOneFKToUniqueKeyPrincipalUniqueKey1, p.OneToOneFKToUniqueKeyPrincipalUniqueKey2 }) - .HasForeignKey(d => new { d.OneToOneFKToUniqueKeyDependentFK1, d.OneToOneFKToUniqueKeyDependentFK2 }); + .HasForeignKey(d => new { d.OneToOneFKToUniqueKeyDependentFK1, d.OneToOneFKToUniqueKeyDependentFK2 }) + .HasConstraintName("FK_OneToOneFKToUniqueKeyDependent"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneFKToUniqueKeyPrincipalID1, e.OneToOneFKToUniqueKeyPrincipalID2 }); + entity.HasKey(e => new { e.OneToOneFKToUniqueKeyPrincipalID1, e.OneToOneFKToUniqueKeyPrincipalID2 }) + .HasName("PK_OneToOneFKToUniqueKeyPrincipal"); entity.HasIndex(e => new { e.OneToOneFKToUniqueKeyPrincipalUniqueKey1, e.OneToOneFKToUniqueKeyPrincipalUniqueKey2 }) .HasName("UK_OneToOneFKToUniqueKeyPrincipal") @@ -95,12 +101,14 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOnePrincipalID1, e.OneToOnePrincipalID2 }); + entity.HasKey(e => new { e.OneToOnePrincipalID1, e.OneToOnePrincipalID2 }) + .HasName("PK_OneToOnePrincipal"); }); modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneSeparateFKDependentID1, e.OneToOneSeparateFKDependentID2 }); + entity.HasKey(e => new { e.OneToOneSeparateFKDependentID1, e.OneToOneSeparateFKDependentID2 }) + .HasName("PK_OneToOneSeparateFKDependent"); entity.HasIndex(e => new { e.OneToOneSeparateFKDependentFK1, e.OneToOneSeparateFKDependentFK2 }) .HasName("UK_OneToOneSeparateFKDependent") @@ -109,7 +117,8 @@ namespace E2ETest.Namespace modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToOneSeparateFKPrincipalID1, e.OneToOneSeparateFKPrincipalID2 }); + entity.HasKey(e => new { e.OneToOneSeparateFKPrincipalID1, e.OneToOneSeparateFKPrincipalID2 }) + .HasName("PK_OneToOneSeparateFKPrincipal"); }); modelBuilder.Entity(entity => diff --git a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/SqlServerDatabaseModelFactoryTest.cs b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/SqlServerDatabaseModelFactoryTest.cs index 75f20f08c60..aee5ae8e7ca 100644 --- a/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/SqlServerDatabaseModelFactoryTest.cs +++ b/test/EntityFramework.MicrosoftSqlServer.Design.FunctionalTests/SqlServerDatabaseModelFactoryTest.cs @@ -105,6 +105,13 @@ public void It_reads_indexes() Assert.True(clusteredIndex.IsClustered); Assert.Equal(new List { "Location", "Name" }, clusteredIndex.Columns.Select(c => c.Name).ToList()); }, + pkIndex => + { + Assert.StartsWith("PK__Place", pkIndex.Name); + Assert.True(pkIndex.IsUnique); + Assert.False(pkIndex.IsClustered); + Assert.Equal(new List { "Id" }, pkIndex.Columns.Select(c => c.Name).ToList()); + }, unique => { Assert.True(unique.IsUnique); diff --git a/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/AllFluentApi/OneToMany/OneToManyFluentApiContext.expected b/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/AllFluentApi/OneToMany/OneToManyFluentApiContext.expected index 6b66ece96ec..099dbc61d11 100644 --- a/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/AllFluentApi/OneToMany/OneToManyFluentApiContext.expected +++ b/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/AllFluentApi/OneToMany/OneToManyFluentApiContext.expected @@ -14,7 +14,8 @@ namespace E2E.Sqlite { modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }); + entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }) + .HasName("sqlite_autoindex_OneToManyDependent_1"); entity.Property(e => e.OneToManyDependentID1).HasColumnType("INT"); @@ -35,7 +36,8 @@ namespace E2E.Sqlite modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }); + entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }) + .HasName("sqlite_autoindex_OneToManyPrincipal_1"); entity.Property(e => e.OneToManyPrincipalID1).HasColumnType("INT"); diff --git a/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/UseAttributesInsteadOfFluentApi/OneToMany/OneToManyAttributesContext.expected b/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/UseAttributesInsteadOfFluentApi/OneToMany/OneToManyAttributesContext.expected index e120c7afdbd..2542cd2ee8a 100644 --- a/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/UseAttributesInsteadOfFluentApi/OneToMany/OneToManyAttributesContext.expected +++ b/test/EntityFramework.Sqlite.Design.FunctionalTests/ReverseEngineering/Expected/UseAttributesInsteadOfFluentApi/OneToMany/OneToManyAttributesContext.expected @@ -14,7 +14,8 @@ namespace E2E.Sqlite { modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }); + entity.HasKey(e => new { e.OneToManyDependentID1, e.OneToManyDependentID2 }) + .HasName("sqlite_autoindex_OneToManyDependent_1"); entity.Property(e => e.OneToManyDependentID1).HasColumnType("INT"); @@ -29,7 +30,8 @@ namespace E2E.Sqlite modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }); + entity.HasKey(e => new { e.OneToManyPrincipalID1, e.OneToManyPrincipalID2 }) + .HasName("sqlite_autoindex_OneToManyPrincipal_1"); entity.Property(e => e.OneToManyPrincipalID1).HasColumnType("INT");