private IConventionForeignKey CreateSkipNavigationForeignKey( IConventionSkipNavigation skipNavigation, IConventionEntityTypeBuilder joinEntityTypeBuilder, IConventionProperty partitionKeyProperty) { if (skipNavigation.ForeignKey != null && !skipNavigation.Builder.CanSetForeignKey(null)) { return(skipNavigation.ForeignKey); } var principalKey = skipNavigation.DeclaringEntityType.FindPrimaryKey(); if (principalKey == null || principalKey.Properties.All(p => p.Name != partitionKeyProperty.Name)) { return(CreateSkipNavigationForeignKey(skipNavigation, joinEntityTypeBuilder)); } if (skipNavigation.ForeignKey?.Properties.Contains(partitionKeyProperty) == true) { return(skipNavigation.ForeignKey); } var dependentProperties = new IConventionProperty[principalKey.Properties.Count]; for (var i = 0; i < principalKey.Properties.Count; i++) { var principalProperty = principalKey.Properties[i]; if (principalProperty.Name == partitionKeyProperty.Name) { dependentProperties[i] = partitionKeyProperty; } else { dependentProperties[i] = joinEntityTypeBuilder.CreateUniqueProperty( principalProperty.ClrType, principalProperty.Name, required: true) !.Metadata; } } var foreignKey = joinEntityTypeBuilder.HasRelationship(skipNavigation.DeclaringEntityType, dependentProperties, principalKey) ! .IsUnique(false) ! .Metadata; skipNavigation.Builder.HasForeignKey(foreignKey); return(foreignKey); }
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 = entityTypeBuilder.CreateUniqueProperty(typeof(int), "Id", required: true).Metadata; } keyProperties.Clear(); keyProperties.Add(shadowProperty); } var extraProperty = keyProperties[0]; keyProperties.RemoveAt(0); keyProperties.AddRange(definingFk.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) { keyProperties.AddRange(manyToManyForeignKeys.SelectMany(fk => fk.Properties)); } } ProcessKeyProperties(keyProperties, entityType); if (keyProperties.Count > 0) { entityTypeBuilder.PrimaryKey(keyProperties); } }