private IConventionRelationshipBuilder DiscoverProperties( IConventionRelationshipBuilder relationshipBuilder, IConventionContext context) { var foreignKey = relationshipBuilder.Metadata; if (!ConfigurationSource.Convention.Overrides(foreignKey.GetPropertiesConfigurationSource())) { var batch = context.DelayConventions(); using (var foreignKeyReference = batch.Track(foreignKey)) { foreach (var fkProperty in foreignKey.Properties) { if (ConfigurationSource.Convention.Overrides(fkProperty.GetTypeConfigurationSource()) && fkProperty.IsShadowProperty() && fkProperty.ClrType.IsNullableType() == foreignKey.IsRequired && fkProperty.GetContainingForeignKeys().All(otherFk => otherFk.IsRequired == foreignKey.IsRequired)) { var newType = fkProperty.ClrType.MakeNullable(!foreignKey.IsRequired); if (fkProperty.ClrType != newType) { fkProperty.DeclaringEntityType.Builder.Property( newType, fkProperty.Name, fkProperty.GetConfigurationSource() == ConfigurationSource.DataAnnotation); } } } batch.Dispose(); return(foreignKeyReference.Object?.Builder); } } var invertible = true; if (foreignKey.DeclaringEntityType.DefiningEntityType == foreignKey.PrincipalEntityType || foreignKey.IsOwnership || foreignKey.DeclaringEntityType.IsKeyless || (!foreignKey.IsUnique && !ConfigurationSource.Convention.Overrides(foreignKey.GetIsUniqueConfigurationSource())) || foreignKey.PrincipalToDependent?.IsCollection() == true || foreignKey.DeclaringEntityType.FindOwnership() != null) { relationshipBuilder = relationshipBuilder.HasEntityTypes( foreignKey.PrincipalEntityType, foreignKey.DeclaringEntityType); invertible = false; } else if (ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) && (foreignKey.PrincipalEntityType.DefiningEntityType == foreignKey.DeclaringEntityType || (foreignKey.PrincipalEntityType.FindOwnership() != null && foreignKey.PrincipalToDependent != null && foreignKey.DependentToPrincipal == null))) { var invertedRelationshipBuilder = relationshipBuilder.HasEntityTypes( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType); if (invertedRelationshipBuilder != null) { return(invertedRelationshipBuilder); } } var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true); if (foreignKeyProperties == null) { if (invertible && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null) { var invertedRelationshipBuilder = relationshipBuilder .HasEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType); var invertedFk = invertedRelationshipBuilder?.Metadata; if (invertedFk?.IsSelfReferencing() == true) { invertedRelationshipBuilder = invertedRelationshipBuilder.HasNavigations( invertedFk.PrincipalToDependent?.Name, invertedFk.DependentToPrincipal?.Name); } return(invertedRelationshipBuilder ?? (foreignKey.Builder == null ? null : relationshipBuilder)); } } if (foreignKey.IsUnique && foreignKey.DeclaringEntityType.BaseType == null && !foreignKey.IsSelfReferencing()) { // Try to use PK properties if principal end is not ambiguous if (!foreignKey.IsOwnership && (!ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) || foreignKey.DeclaringEntityType.DefiningEntityType == foreignKey.PrincipalEntityType)) { foreignKeyProperties = GetCompatiblePrimaryKeyProperties( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, foreignKey.PrincipalKey.Properties); } else if (invertible) { foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true, matchPk: true); var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false, matchPk: true); if (candidatePropertiesOnPrincipal != null) { if (foreignKeyProperties == null) { using (var batch = context.DelayConventions()) { var invertedRelationshipBuilder = relationshipBuilder .HasEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType); return(batch.Run( invertedRelationshipBuilder.HasForeignKey(candidatePropertiesOnPrincipal).Metadata) ?.Builder); } } foreignKeyProperties = null; ((ForeignKey)relationshipBuilder.Metadata).SetPrincipalEndConfigurationSource(null); } } } if (foreignKeyProperties == null && invertible && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { ((ForeignKey)relationshipBuilder.Metadata).SetPrincipalEndConfigurationSource(null); } } else if (invertible && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null) { // Principal end is ambiguous foreignKeyProperties = null; ((ForeignKey)relationshipBuilder.Metadata).SetPrincipalEndConfigurationSource(null); } } if (foreignKeyProperties == null) { return(ReuniquifyTemporaryProperties(foreignKey, force: false)); } var conflictingFKCount = foreignKey.DeclaringEntityType.FindForeignKeys(foreignKeyProperties) .Concat( foreignKey.DeclaringEntityType.GetDerivedTypes() .SelectMany(et => et.FindDeclaredForeignKeys(foreignKeyProperties))) .Count(); if (foreignKey.Properties.SequenceEqual(foreignKeyProperties)) { return(conflictingFKCount > 1 ? ReuniquifyTemporaryProperties(foreignKey, force: true) : relationshipBuilder); } if (conflictingFKCount > 0) { return(ReuniquifyTemporaryProperties(foreignKey, force: false)); } var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties); if (newRelationshipBuilder != null) { return(newRelationshipBuilder); } return(relationshipBuilder.Metadata.Builder == null ? null : relationshipBuilder); }
/// <summary> /// Called after the ownership value for a foreign key is changed. /// </summary> /// <param name="relationshipBuilder"> The builder for the foreign key. </param> /// <param name="context"> Additional information associated with convention execution. </param> public virtual void ProcessForeignKeyOwnershipChanged( IConventionRelationshipBuilder relationshipBuilder, IConventionContext <IConventionRelationshipBuilder> context) { TryConfigurePrimaryKey(relationshipBuilder.Metadata.DeclaringEntityType.Builder); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public abstract void ProcessNavigationAdded( [NotNull] IConventionRelationshipBuilder relationshipBuilder, [NotNull] IConventionNavigation navigation, [NotNull] TAttribute attribute, [NotNull] IConventionContext <IConventionNavigation> context);
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual IConventionNavigation OnNavigationAdded( [NotNull] IConventionRelationshipBuilder relationshipBuilder, [NotNull] IConventionNavigation navigation) => _scope.OnNavigationAdded(relationshipBuilder, navigation);
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual IConventionRelationshipBuilder OnForeignKeyPrincipalEndChanged( [NotNull] IConventionRelationshipBuilder relationshipBuilder) => _scope.OnForeignKeyPrincipalEndChanged(relationshipBuilder);
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual IConventionRelationshipBuilder OnForeignKeyOwnershipChanged( [NotNull] IConventionRelationshipBuilder relationshipBuilder) => _scope.OnForeignKeyOwnershipChanged(relationshipBuilder);
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual IConventionRelationshipBuilder OnForeignKeyRequirednessChanged( [NotNull] IConventionRelationshipBuilder relationshipBuilder) => _scope.OnForeignKeyRequirednessChanged(relationshipBuilder);
/// <summary> /// Called after the principal end of a foreign key is changed. /// </summary> /// <param name="relationshipBuilder"> The builder for the foreign key. </param> /// <param name="context"> Additional information associated with convention execution. </param> public virtual void ProcessForeignKeyPrincipalEndChanged( IConventionRelationshipBuilder relationshipBuilder, IConventionContext <IConventionRelationshipBuilder> context) { ProcessForeignKeyAdded(relationshipBuilder, context); }