/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder) { var foreignKey = relationshipBuilder.Metadata; var foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true); if (foreignKeyProperties == null) { // Try to invert if one to one or can be converted to one to one if (foreignKey.IsUnique || (foreignKey.PrincipalToDependent == null)) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); return invertedRelationshipBuilder ?? relationshipBuilder; } } // Try to use PK properties if principal end is not ambiguous if (foreignKey.IsUnique && !foreignKey.IsSelfReferencing() && !ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { foreignKeyProperties = GetCompatiblePrimaryKeyProperties( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, foreignKey.PrincipalKey.Properties); } } if ((foreignKeyProperties == null) || foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(foreignKeyProperties).Any()) { return relationshipBuilder; } if (ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) && !foreignKey.IsSelfReferencing() && (foreignKey.PrincipalToDependent?.IsCollection() != true)) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { // Ambiguous principal end if (relationshipBuilder.Metadata.GetPrincipalEndConfigurationSource() == ConfigurationSource.Convention) { relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null); } return relationshipBuilder; } } var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention); if (newRelationshipBuilder != null) { return newRelationshipBuilder; } return relationshipBuilder; }
private InternalRelationshipBuilder DiscoverProperties(InternalRelationshipBuilder relationshipBuilder) { var foreignKey = relationshipBuilder.Metadata; if (!ConfigurationSource.Convention.Overrides(foreignKey.GetPropertiesConfigurationSource())) { using (var batch = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.StartBatch()) { using (var foreignKeyReference = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.Tracker.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( fkProperty.Name, fkProperty.ClrType.MakeNullable(!foreignKey.IsRequired), fkProperty.GetConfigurationSource(), ConfigurationSource.Convention); } } } batch.Run(); return(foreignKeyReference.Object?.Builder); } } } var invertable = 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.RelatedEntityTypes( foreignKey.PrincipalEntityType, foreignKey.DeclaringEntityType, ConfigurationSource.Convention); invertable = 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.RelatedEntityTypes( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); if (invertedRelationshipBuilder != null) { return(invertedRelationshipBuilder); } } var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true); if (foreignKeyProperties == null) { if (invertable && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); var invertedFk = invertedRelationshipBuilder?.Metadata; if (invertedFk?.IsSelfReferencing() == true) { invertedRelationshipBuilder = invertedRelationshipBuilder.Navigations( invertedFk.PrincipalToDependent?.Name, invertedFk.DependentToPrincipal?.Name, ConfigurationSource.Convention); } 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 (invertable) { foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true, matchPk: true); var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false, matchPk: true); if (candidatePropertiesOnPrincipal != null) { if (foreignKeyProperties == null) { using (var batch = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.StartBatch()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); return(batch.Run(invertedRelationshipBuilder.HasForeignKey(candidatePropertiesOnPrincipal, foreignKey.PrincipalEntityType, ConfigurationSource.Convention))); } } foreignKeyProperties = null; relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null); } } } if (foreignKeyProperties == null && invertable && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null); } } else if (invertable && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null) { // Principal end is ambiguous foreignKeyProperties = null; relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null); } } if (foreignKeyProperties == null) { return(ReuniquifyTemporaryProperties(foreignKey, force: false)); } var conflictingFKCount = foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(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, ConfigurationSource.Convention); if (newRelationshipBuilder != null) { return(newRelationshipBuilder); } return(relationshipBuilder.Metadata.Builder == null ? null : relationshipBuilder); }
private InternalRelationshipBuilder DiscoverProperties(InternalRelationshipBuilder relationshipBuilder) { var foreignKey = relationshipBuilder.Metadata; if (!ConfigurationSource.Convention.Overrides(foreignKey.GetForeignKeyPropertiesConfigurationSource())) { foreach (var fkProperty in foreignKey.Properties) { if (fkProperty.GetTypeConfigurationSource() == null && (fkProperty.IsShadowProperty || fkProperty.PropertyInfo == null && fkProperty.GetFieldInfoConfigurationSource() == ConfigurationSource.Convention) && fkProperty.ClrType.IsNullableType() == foreignKey.IsRequired) { fkProperty.DeclaringEntityType.Builder.Property( fkProperty.Name, fkProperty.ClrType.MakeNullable(!foreignKey.IsRequired), fkProperty.GetConfigurationSource(), ConfigurationSource.Convention); } } return(relationshipBuilder); } var invertable = true; if (foreignKey.DeclaringEntityType.DefiningEntityType == foreignKey.PrincipalEntityType || foreignKey.IsOwnership || foreignKey.DeclaringEntityType.IsQueryType || foreignKey.IsSelfReferencing() || foreignKey.PrincipalToDependent?.IsCollection() == true || foreignKey.DeclaringEntityType.FindOwnership() != null) { relationshipBuilder = relationshipBuilder.RelatedEntityTypes( foreignKey.PrincipalEntityType, foreignKey.DeclaringEntityType, ConfigurationSource.Convention); invertable = 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.RelatedEntityTypes( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); if (invertedRelationshipBuilder != null) { return(invertedRelationshipBuilder); } } var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true); if (foreignKeyProperties == null) { // Try to invert if one to one or can be converted to one to one if (invertable && (foreignKey.IsUnique || foreignKey.PrincipalToDependent == null) && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); 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 (invertable) { foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true, matchPk: true); var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false, matchPk: true); if (candidatePropertiesOnPrincipal != null) { if (foreignKeyProperties == null) { using (var batch = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.StartBatch()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); return(batch.Run(invertedRelationshipBuilder.HasForeignKey(candidatePropertiesOnPrincipal, foreignKey.PrincipalEntityType, ConfigurationSource.Convention))); } } foreignKeyProperties = null; } } } } return(SetForeignKeyProperties(relationshipBuilder, foreignKeyProperties)); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder) { var foreignKey = relationshipBuilder.Metadata; if (!ConfigurationSource.Convention.Overrides(foreignKey.GetForeignKeyPropertiesConfigurationSource())) { var conflictingForeignKeys = foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(foreignKey.Properties) .Where(fk => ConfigurationSource.Convention.Overrides(fk.GetForeignKeyPropertiesConfigurationSource())) .ToList(); foreach (var conflictingForeignKey in conflictingForeignKeys) { conflictingForeignKey.Builder.HasForeignKey((IReadOnlyList <Property>)null, ConfigurationSource.Convention); } return(relationshipBuilder); } var invertable = true; if (foreignKey.DeclaringEntityType.DefiningEntityType == foreignKey.PrincipalEntityType || foreignKey.IsOwnership || foreignKey.DeclaringEntityType.IsQueryType || foreignKey.IsSelfReferencing() || foreignKey.PrincipalToDependent?.IsCollection() == true || foreignKey.DeclaringEntityType.FindOwnership() != null) { relationshipBuilder = relationshipBuilder.RelatedEntityTypes( foreignKey.PrincipalEntityType, foreignKey.DeclaringEntityType, ConfigurationSource.Convention); invertable = 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.RelatedEntityTypes( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); if (invertedRelationshipBuilder != null) { return(invertedRelationshipBuilder); } } var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true); if (foreignKeyProperties == null) { // Try to invert if one to one or can be converted to one to one if (invertable && (foreignKey.IsUnique || foreignKey.PrincipalToDependent == null) && ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); 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 (!ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) || foreignKey.DeclaringEntityType.DefiningEntityType == foreignKey.PrincipalEntityType || foreignKey.IsOwnership) { foreignKeyProperties = GetCompatiblePrimaryKeyProperties( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, foreignKey.PrincipalKey.Properties); } else if (invertable) { foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true, matchPk: true); var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false, matchPk: true); if (candidatePropertiesOnPrincipal != null) { if (foreignKeyProperties == null) { using (var batch = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.StartBatch()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); return(batch.Run(invertedRelationshipBuilder.HasForeignKey(candidatePropertiesOnPrincipal, foreignKey.PrincipalEntityType, ConfigurationSource.Convention))); } } foreignKeyProperties = null; } } } } relationshipBuilder = SetForeignKeyProperties(relationshipBuilder, foreignKeyProperties); foreignKey = relationshipBuilder?.Metadata; if (relationshipBuilder == null || foreignKey.GetForeignKeyPropertiesConfigurationSource() != null) { return(relationshipBuilder); } using (var batch = foreignKey.DeclaringEntityType.Model.ConventionDispatcher.StartBatch()) { var newTemporaryProperties = foreignKey.DeclaringEntityType.Builder.ReUniquifyTemporaryProperties( foreignKey.Properties, foreignKey.PrincipalKey.Properties, foreignKey.IsRequired, GetPropertyBaseName(foreignKey)); return(newTemporaryProperties != null ? batch.Run( relationshipBuilder.HasForeignKey( newTemporaryProperties, foreignKey.DeclaringEntityType, null)) : relationshipBuilder); } }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder) { var foreignKey = relationshipBuilder.Metadata; var foreignKeyProperties = FindCandidateForeignKeyProperties(foreignKey, onDependent: true); if (foreignKeyProperties == null) { // Try to invert if one to one or can be converted to one to one if (foreignKey.IsUnique || (foreignKey.PrincipalToDependent == null)) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { var invertedRelationshipBuilder = relationshipBuilder .RelatedEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention); if (invertedRelationshipBuilder != null) { return(invertedRelationshipBuilder); } return(foreignKey.Builder == null ? null : relationshipBuilder); } } // Try to use PK properties if principal end is not ambiguous if (foreignKey.IsUnique && !foreignKey.IsSelfReferencing() && !ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource())) { foreignKeyProperties = GetCompatiblePrimaryKeyProperties( foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, foreignKey.PrincipalKey.Properties); } } if ((foreignKeyProperties == null) || foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(foreignKeyProperties).Any()) { return(relationshipBuilder); } if (ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) && !foreignKey.IsSelfReferencing() && (foreignKey.PrincipalToDependent?.IsCollection() != true)) { var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false); if (candidatePropertiesOnPrincipal != null && !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()) { // Ambiguous principal end if (relationshipBuilder.Metadata.GetPrincipalEndConfigurationSource() == ConfigurationSource.Convention) { relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null); } return(relationshipBuilder); } } var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention); if (newRelationshipBuilder != null) { return(newRelationshipBuilder); } if (relationshipBuilder.Metadata.Builder == null) { return(null); } return(relationshipBuilder); }