public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = relationshipBuilder.Metadata;

            if (!foreignKey.Properties.All(fk => fk.IsShadowProperty))
            {
                return(relationshipBuilder);
            }

            var foreignKeyProperties = FindCandidateForeignKeyProperties(
                relationshipBuilder.Metadata, onDependent: true);

            if (foreignKey.IsUnique &&
                !foreignKey.IsSelfPrimaryKeyReferencing())
            {
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(
                    relationshipBuilder.Metadata, onDependent: false);

                if (ShouldInvert(relationshipBuilder.Metadata, foreignKeyProperties, candidatePropertiesOnPrincipal) &&
                    relationshipBuilder.CanInvert(candidatePropertiesOnPrincipal, ConfigurationSource.Convention))
                {
                    relationshipBuilder = relationshipBuilder.DependentEntityType(relationshipBuilder.Metadata.PrincipalEntityType, ConfigurationSource.Convention);

                    if (candidatePropertiesOnPrincipal != null)
                    {
                        relationshipBuilder = relationshipBuilder.HasForeignKey(
                            candidatePropertiesOnPrincipal, ConfigurationSource.Convention);
                    }

                    Debug.Assert(relationshipBuilder != null);
                    return(relationshipBuilder);
                }

                if (foreignKeyProperties == null)
                {
                    foreignKeyProperties = GetCompatiblePrimaryKeyProperties(
                        relationshipBuilder.Metadata.DeclaringEntityType,
                        relationshipBuilder.Metadata.PrincipalEntityType,
                        relationshipBuilder.Metadata.PrincipalKey.Properties);
                }
            }

            if ((foreignKeyProperties == null) ||
                (relationshipBuilder.Metadata.DeclaringEntityType.FindForeignKey(foreignKeyProperties, foreignKey.PrincipalKey, foreignKey.PrincipalEntityType) != null))
            {
                return(relationshipBuilder);
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention);

            if (newRelationshipBuilder != null)
            {
                return(newRelationshipBuilder);
            }

            return(relationshipBuilder);
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = (IForeignKey)relationshipBuilder.Metadata;
            if (!foreignKey.Properties.All(fk => fk.IsShadowProperty))
            {
                return relationshipBuilder;
            }

            var foreignKeyProperties = FindCandidateForeignKeyProperties(
                relationshipBuilder.Metadata, onDependent: true);
            if (foreignKey.IsUnique
                && !foreignKey.IsSelfPrimaryKeyReferencing())
            {
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(
                    relationshipBuilder.Metadata, onDependent: false);

                if (ShouldInvert(relationshipBuilder.Metadata, foreignKeyProperties, candidatePropertiesOnPrincipal)
                    && relationshipBuilder.CanInvert(candidatePropertiesOnPrincipal, ConfigurationSource.Convention))
                {
                    relationshipBuilder = relationshipBuilder.DependentEntityType(relationshipBuilder.Metadata.PrincipalEntityType, ConfigurationSource.Convention);

                    if (candidatePropertiesOnPrincipal != null)
                    {
                        relationshipBuilder = relationshipBuilder.HasForeignKey(
                            candidatePropertiesOnPrincipal, ConfigurationSource.Convention);
                    }

                    Debug.Assert(relationshipBuilder != null);
                    return relationshipBuilder;
                }

                if (foreignKeyProperties == null)
                {
                    foreignKeyProperties = GetCompatiblePrimaryKeyProperties(
                        relationshipBuilder.Metadata.DeclaringEntityType,
                        relationshipBuilder.Metadata.PrincipalEntityType,
                        relationshipBuilder.Metadata.PrincipalKey.Properties);
                }
            }

            if (foreignKeyProperties == null
                || relationshipBuilder.Metadata.DeclaringEntityType.FindForeignKey(foreignKeyProperties, foreignKey.PrincipalKey, foreignKey.PrincipalEntityType) != null)
            {
                return relationshipBuilder;
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention);
            if (newRelationshipBuilder != null)
            {
                return newRelationshipBuilder;
            }

            return relationshipBuilder;
        }
        private InternalRelationshipBuilder SetForeignKeyProperties(
            InternalRelationshipBuilder relationshipBuilder, IReadOnlyList <Property> foreignKeyProperties)
        {
            var foreignKey = relationshipBuilder.Metadata;

            if (ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) &&
                foreignKey.DeclaringEntityType.DefiningEntityType != foreignKey.PrincipalEntityType &&
                !foreignKey.IsOwnership &&
                !foreignKey.DeclaringEntityType.IsKeyless &&
                !foreignKey.IsSelfReferencing() &&
                foreignKey.PrincipalToDependent?.IsCollection() != true &&
                foreignKey.DeclaringEntityType.FindOwnership() == null)
            {
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false);
                if (foreignKeyProperties == null ||
                    (candidatePropertiesOnPrincipal != null &&
                     !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any()))
                {
                    // Principal end is ambiguous
                    relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null);
                    foreignKeyProperties = 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 SetForeignKeyProperties(
            InternalRelationshipBuilder relationshipBuilder, IReadOnlyList <Property> foreignKeyProperties)
        {
            if (foreignKeyProperties == null)
            {
                return(relationshipBuilder);
            }

            var foreignKey = relationshipBuilder.Metadata;

            if (ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) &&
                foreignKey.DeclaringEntityType.DefiningEntityType != foreignKey.PrincipalEntityType &&
                !foreignKey.IsOwnership &&
                !foreignKey.DeclaringEntityType.IsQueryType &&
                !foreignKey.IsSelfReferencing() &&
                foreignKey.PrincipalToDependent?.IsCollection() != true &&
                foreignKey.DeclaringEntityType.FindOwnership() == null)
            {
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(foreignKey, onDependent: false);
                if (candidatePropertiesOnPrincipal != null &&
                    !foreignKey.PrincipalEntityType.FindForeignKeysInHierarchy(candidatePropertiesOnPrincipal).Any())
                {
                    // Principal end became ambiguous
                    if (relationshipBuilder.Metadata.GetPrincipalEndConfigurationSource() == ConfigurationSource.Convention)
                    {
                        relationshipBuilder.Metadata.SetPrincipalEndConfigurationSource(null);
                    }
                    return(relationshipBuilder);
                }
            }

            if (foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(foreignKeyProperties).Any())
            {
                return(relationshipBuilder);
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention);

            if (newRelationshipBuilder != null)
            {
                return(newRelationshipBuilder);
            }

            if (relationshipBuilder.Metadata.Builder == null)
            {
                return(null);
            }

            return(relationshipBuilder);
        }
        private InternalRelationshipBuilder DiscoverProperties(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = relationshipBuilder.Metadata;

            if (!ConfigurationSource.Convention.Overrides(foreignKey.GetForeignKeyPropertiesConfigurationSource()))
            {
                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);
        }
Exemple #6
0
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = relationshipBuilder.Metadata;

            if (!foreignKey.Properties.All(fk => fk.IsShadowProperty))
            {
                return(relationshipBuilder);
            }

            var foreignKeyProperties = FindCandidateForeignKeyProperties(
                foreignKey, onDependent: true);

            if (foreignKey.IsUnique &&
                !foreignKey.IsSelfPrimaryKeyReferencing())
            {
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(
                    foreignKey, onDependent: false);

                if (candidatePropertiesOnPrincipal != null)
                {
                    if ((foreignKeyProperties == null) &&
                        relationshipBuilder.CanInvert(candidatePropertiesOnPrincipal, ConfigurationSource.Convention))
                    {
                        // Invert only if principal side has matching property & dependent does not have
                        relationshipBuilder = relationshipBuilder
                                              .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.Convention)
                                              .HasForeignKey(candidatePropertiesOnPrincipal, ConfigurationSource.Convention);

                        Debug.Assert(relationshipBuilder != null);
                        return(relationshipBuilder);
                    }

                    // Return if both sides have matching property
                    return(relationshipBuilder);
                }

                // Only match with PK if the principal end is set
                if ((!ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalEndConfigurationSource()) ||
                     !ConfigurationSource.Convention.Overrides(foreignKey.GetPrincipalKeyConfigurationSource())) &&
                    (foreignKeyProperties == null))
                {
                    foreignKeyProperties = GetCompatiblePrimaryKeyProperties(
                        foreignKey.DeclaringEntityType,
                        foreignKey.PrincipalEntityType,
                        foreignKey.PrincipalKey.Properties);
                }
            }
            else if ((foreignKey.DependentToPrincipal != null) &&
                     !foreignKey.DependentToPrincipal.IsCollection() &&
                     (foreignKey.PrincipalToDependent == null))
            {
                // Single reference navigation which can be converted to one to one
                var candidatePropertiesOnPrincipal = FindCandidateForeignKeyProperties(
                    foreignKey, onDependent: false);

                if (candidatePropertiesOnPrincipal != null)
                {
                    if ((foreignKeyProperties == null) &&
                        relationshipBuilder.CanInvert(candidatePropertiesOnPrincipal, ConfigurationSource.Convention))
                    {
                        // Invert and set one to one if principal side has matching property & dependent side does not have
                        relationshipBuilder = relationshipBuilder
                                              .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.Convention)
                                              .IsUnique(true, ConfigurationSource.Convention)
                                              .HasForeignKey(candidatePropertiesOnPrincipal, ConfigurationSource.Convention);

                        Debug.Assert(relationshipBuilder != null);
                        return(relationshipBuilder);
                    }
                }
            }

            if ((foreignKeyProperties == null) ||
                (foreignKey.DeclaringEntityType.FindForeignKey(foreignKeyProperties, foreignKey.PrincipalKey, foreignKey.PrincipalEntityType) != null))
            {
                return(relationshipBuilder);
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention);

            if (newRelationshipBuilder != null)
            {
                return(newRelationshipBuilder);
            }

            return(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;

            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);

                        if (invertedRelationshipBuilder != null)
                        {
                            return(invertedRelationshipBuilder);
                        }

                        return(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);
            }
        }
Exemple #8
0
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));

            var foreignKey = relationshipBuilder.Metadata;

            var fkPropertyOnPrincipal = FindForeignKeyAttributeOnProperty(foreignKey.PrincipalEntityType, foreignKey.PrincipalToDependent?.Name);
            var fkPropertyOnDependent = FindForeignKeyAttributeOnProperty(foreignKey.DeclaringEntityType, foreignKey.DependentToPrincipal?.Name);

            if (!string.IsNullOrEmpty(fkPropertyOnDependent) &&
                !string.IsNullOrEmpty(fkPropertyOnPrincipal))
            {
                // TODO: Log Error that unable to determine principal end based on foreign key attributes on properties
                SplitNavigationsInSeparateRelationships(relationshipBuilder);

                return(null);
            }

            var fkPropertiesOnPrincipalToDependent = FindCandidateDependentPropertiesThroughNavigation(relationshipBuilder, pointsToPrincipal: false);
            var fkPropertiesOnDependentToPrincipal = FindCandidateDependentPropertiesThroughNavigation(relationshipBuilder, pointsToPrincipal: true);

            if (fkPropertiesOnDependentToPrincipal != null &&
                fkPropertiesOnPrincipalToDependent != null &&
                !fkPropertiesOnDependentToPrincipal.SequenceEqual(fkPropertiesOnPrincipalToDependent))
            {
                // TODO: Log error that foreign key properties on both navigations do not match
                SplitNavigationsInSeparateRelationships(relationshipBuilder);

                return(null);
            }

            var fkPropertiesOnNavigation = fkPropertiesOnDependentToPrincipal ?? fkPropertiesOnPrincipalToDependent;

            InternalRelationshipBuilder newRelationshipBuilder = null;

            if (fkPropertiesOnNavigation == null ||
                fkPropertiesOnNavigation.Count == 0)
            {
                if (fkPropertyOnDependent == null &&
                    fkPropertyOnPrincipal == null)
                {
                    return(relationshipBuilder);
                }
                if (fkPropertyOnDependent != null)
                {
                    newRelationshipBuilder = relationshipBuilder.HasForeignKey(new List <string> {
                        fkPropertyOnDependent
                    }, ConfigurationSource.DataAnnotation);
                }
                else
                {
                    newRelationshipBuilder = relationshipBuilder
                                             .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                                             ?.HasForeignKey(new List <string> {
                        fkPropertyOnPrincipal
                    }, ConfigurationSource.DataAnnotation);
                }
            }
            else
            {
                if (fkPropertyOnDependent == null &&
                    fkPropertyOnPrincipal == null)
                {
                    if (fkPropertiesOnNavigation.All(p => foreignKey.DeclaringEntityType.FindProperty(p) != null) ||
                        fkPropertiesOnNavigation.Any(p => foreignKey.PrincipalEntityType.FindProperty(p) == null))
                    {
                        newRelationshipBuilder = relationshipBuilder.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder
                                                 .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                                                 ?.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                }
                else
                {
                    if (fkPropertiesOnNavigation.Count != 1 ||
                        !string.Equals(fkPropertiesOnNavigation.First(), fkPropertyOnDependent ?? fkPropertyOnPrincipal))
                    {
                        // TODO: Log error that mismatch in foreignKey Attribute on navigation and property
                        SplitNavigationsInSeparateRelationships(relationshipBuilder);

                        return(null);
                    }

                    if (fkPropertyOnDependent != null)
                    {
                        newRelationshipBuilder = relationshipBuilder.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder
                                                 .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                                                 ?.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                }
            }
            return(newRelationshipBuilder ?? 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);

                        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;
        }
        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())
            {
                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);
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));

            var foreignKey = relationshipBuilder.Metadata;

            var fkPropertyOnPrincipal = FindForeignKeyAttributeOnProperty(foreignKey.PrincipalEntityType, foreignKey.PrincipalToDependent?.Name);
            var fkPropertyOnDependent = FindForeignKeyAttributeOnProperty(foreignKey.DeclaringEntityType, foreignKey.DependentToPrincipal?.Name);

            if (!string.IsNullOrEmpty(fkPropertyOnDependent)
                && !string.IsNullOrEmpty(fkPropertyOnPrincipal))
            {
                // TODO: Log Error that unable to determine principal end based on foreign key attributes on properties
                SplitNavigationsInSeparateRelationships(relationshipBuilder);

                return null;
            }

            var fkPropertiesOnPrincipalToDependent = FindCandidateDependentPropertiesThroughNavigation(relationshipBuilder, pointsToPrincipal: false);
            var fkPropertiesOnDependentToPrincipal = FindCandidateDependentPropertiesThroughNavigation(relationshipBuilder, pointsToPrincipal: true);

            if (fkPropertiesOnDependentToPrincipal != null
                && fkPropertiesOnPrincipalToDependent != null
                && !fkPropertiesOnDependentToPrincipal.SequenceEqual(fkPropertiesOnPrincipalToDependent))
            {
                // TODO: Log error that foreign key properties on both navigations do not match
                SplitNavigationsInSeparateRelationships(relationshipBuilder);

                return null;
            }

            var fkPropertiesOnNavigation = fkPropertiesOnDependentToPrincipal ?? fkPropertiesOnPrincipalToDependent;

            InternalRelationshipBuilder newRelationshipBuilder = null;
            if (fkPropertiesOnNavigation == null
                || fkPropertiesOnNavigation.Count == 0)
            {
                if (fkPropertyOnDependent == null
                    && fkPropertyOnPrincipal == null)
                {
                    return relationshipBuilder;
                }
                if (fkPropertyOnDependent != null)
                {
                    newRelationshipBuilder = relationshipBuilder.HasForeignKey(new List<string> { fkPropertyOnDependent }, ConfigurationSource.DataAnnotation);
                }
                else
                {
                    newRelationshipBuilder = relationshipBuilder
                        .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                        ?.HasForeignKey(new List<string> { fkPropertyOnPrincipal }, ConfigurationSource.DataAnnotation);
                }
            }
            else
            {
                if (fkPropertyOnDependent == null
                    && fkPropertyOnPrincipal == null)
                {
                    if (fkPropertiesOnNavigation.All(p => foreignKey.DeclaringEntityType.FindProperty(p) != null)
                        || fkPropertiesOnNavigation.Any(p => foreignKey.PrincipalEntityType.FindProperty(p) == null))
                    {
                        newRelationshipBuilder = relationshipBuilder.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder
                            .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                            ?.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                }
                else
                {
                    if (fkPropertiesOnNavigation.Count != 1
                        || !string.Equals(fkPropertiesOnNavigation.First(), fkPropertyOnDependent ?? fkPropertyOnPrincipal))
                    {
                        // TODO: Log error that mismatch in foreignKey Attribute on navigation and property
                        SplitNavigationsInSeparateRelationships(relationshipBuilder);

                        return null;
                    }

                    if (fkPropertyOnDependent != null)
                    {
                        newRelationshipBuilder = relationshipBuilder.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder
                            .DependentEntityType(foreignKey.PrincipalEntityType, ConfigurationSource.DataAnnotation)
                            ?.HasForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                }
            }
            return newRelationshipBuilder ?? relationshipBuilder;
        }
Exemple #12
0
        /// <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()))
            {
                return(relationshipBuilder);
            }

            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) &&
                    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);

                        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()) &&
                    foreignKey.DeclaringEntityType.BaseType == null)
                {
                    foreignKeyProperties = GetCompatiblePrimaryKeyProperties(
                        foreignKey.DeclaringEntityType,
                        foreignKey.PrincipalEntityType,
                        foreignKey.PrincipalKey.Properties);
                }
            }

            if (foreignKeyProperties == null &&
                foreignKey.GetForeignKeyPropertiesConfigurationSource() == null)
            {
                var newTemporaryProperties = foreignKey.DeclaringEntityType.Builder.ReUniquifyTemporaryProperties(
                    foreignKey.Properties,
                    foreignKey.PrincipalKey.Properties,
                    foreignKey.IsRequired,
                    foreignKey.DependentToPrincipal == null
                        ? foreignKey.PrincipalEntityType.DisplayName() : foreignKey.DependentToPrincipal.Name);
                return(newTemporaryProperties != null
                    ? relationshipBuilder.HasForeignKey(
                           newTemporaryProperties, foreignKey.DeclaringEntityType, null, runConventions : true)
                    : relationshipBuilder);
            }

            if (foreignKeyProperties == null)
            {
                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);
                }
            }

            if (foreignKey.DeclaringEntityType.FindForeignKeysInHierarchy(foreignKeyProperties).Any())
            {
                return(relationshipBuilder);
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties, ConfigurationSource.Convention);

            if (newRelationshipBuilder != null)
            {
                return(newRelationshipBuilder);
            }

            if (relationshipBuilder.Metadata.Builder == null)
            {
                return(null);
            }

            return(relationshipBuilder);
        }