protected virtual void TryConfigurePrimaryKey([NotNull] IConventionEntityTypeBuilder entityTypeBuilder) { var entityType = entityTypeBuilder.Metadata; if (entityType.BaseType != null || (entityType.IsKeyless && entityType.GetIsKeylessConfigurationSource() != ConfigurationSource.Convention) || !entityTypeBuilder.CanSetPrimaryKey(null)) { return; } List <IConventionProperty>?keyProperties = null; var ownership = entityType.FindOwnership(); if (ownership != null && ownership.DeclaringEntityType != entityType) { ownership = null; } if (ownership?.IsUnique == true) { keyProperties = ownership.Properties.ToList(); } if (keyProperties == null) { var candidateProperties = entityType.GetProperties().Where( p => !p.IsImplicitlyCreated() || !ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())); keyProperties = DiscoverKeyProperties(entityType, candidateProperties).ToList(); if (keyProperties.Count > 1) { Dependencies.Logger.MultiplePrimaryKeyCandidates(keyProperties[0], keyProperties[1]); return; } } if (ownership?.IsUnique == false) { if (keyProperties.Count == 0 || ownership.Properties.Contains(keyProperties.First())) { var primaryKey = entityType.FindPrimaryKey(); var shadowProperty = primaryKey?.Properties.Last(); if (shadowProperty == null || primaryKey !.Properties.Count == 1 || ownership.Properties.Contains(shadowProperty)) { shadowProperty = entityTypeBuilder.CreateUniqueProperty(typeof(int), "Id", required: true) !.Metadata; } keyProperties.Clear(); keyProperties.Add(shadowProperty); } var extraProperty = keyProperties[0]; keyProperties.RemoveAt(0); keyProperties.AddRange(ownership.Properties); keyProperties.Add(extraProperty); } if (keyProperties.Count == 0) { var manyToManyForeignKeys = entityType.GetForeignKeys() .Where(fk => fk.GetReferencingSkipNavigations().Any(n => n.IsCollection)).ToList(); if (manyToManyForeignKeys.Count == 2 && !manyToManyForeignKeys.Any(fk => fk.PrincipalEntityType == entityType)) { keyProperties.AddRange(manyToManyForeignKeys.SelectMany(fk => fk.Properties)); } } for (var i = keyProperties.Count - 1; i >= 0; i--) { var property = keyProperties[i]; for (var j = i - 1; j >= 0; j--) { if (property == keyProperties[j]) { keyProperties.RemoveAt(j); i--; } } } ProcessKeyProperties(keyProperties, entityType); if (keyProperties.Count > 0) { entityTypeBuilder.PrimaryKey(keyProperties); } }
/// <summary> /// Discovers primary key candidates and configures the primary key if found. /// </summary> /// <param name="entityTypeBuilder"> The entity type builder. </param> protected virtual void TryConfigurePrimaryKey([NotNull] IConventionEntityTypeBuilder entityTypeBuilder) { var entityType = entityTypeBuilder.Metadata; if (entityType.BaseType != null || (entityType.IsKeyless && entityType.GetIsKeylessConfigurationSource() != ConfigurationSource.Convention) || !entityTypeBuilder.CanSetPrimaryKey(null)) { return; } List <IConventionProperty> keyProperties = null; var definingFk = entityType.FindDefiningNavigation()?.ForeignKey ?? entityType.FindOwnership(); if (definingFk != null && definingFk.DeclaringEntityType != entityType) { definingFk = null; } if (definingFk?.IsUnique == true) { keyProperties = definingFk.Properties.ToList(); } if (keyProperties == null) { var candidateProperties = entityType.GetProperties().Where( p => !p.IsShadowProperty() || !ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())); keyProperties = DiscoverKeyProperties(entityType, candidateProperties).ToList(); if (keyProperties.Count > 1) { Dependencies.Logger.MultiplePrimaryKeyCandidates(keyProperties[0], keyProperties[1]); return; } } if (definingFk?.IsUnique == false) { if (keyProperties.Count == 0 || definingFk.Properties.Contains(keyProperties.First())) { var primaryKey = entityType.FindPrimaryKey(); var shadowProperty = primaryKey?.Properties.Last(); if (shadowProperty == null || primaryKey.Properties.Count == 1 || definingFk.Properties.Contains(shadowProperty)) { shadowProperty = ((InternalEntityTypeBuilder)entityTypeBuilder) .CreateUniqueProperty("Id", typeof(int), isRequired: true); } keyProperties.Clear(); keyProperties.Add(shadowProperty); } var extraProperty = keyProperties[0]; keyProperties.RemoveAt(0); keyProperties.AddRange(definingFk.Properties); keyProperties.Add(extraProperty); } ProcessKeyProperties(keyProperties, entityType); if (keyProperties.Count > 0) { entityTypeBuilder.PrimaryKey(keyProperties); } }