コード例 #1
0
        /// <summary>
        ///     Called after a navigation property that has an attribute is added to an entity type.
        /// </summary>
        /// <param name="relationshipBuilder"> The builder for the relationship. </param>
        /// <param name="navigation"> The navigation. </param>
        /// <param name="attribute"> The attribute. </param>
        /// <param name="context"> Additional information associated with convention execution. </param>
        public override void ProcessNavigationAdded(
            IConventionRelationshipBuilder relationshipBuilder,
            IConventionNavigation navigation,
            RequiredAttribute attribute,
            IConventionContext <IConventionNavigation> context)
        {
            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));
            Check.NotNull(navigation, nameof(navigation));
            Check.NotNull(attribute, nameof(attribute));

            if (navigation.IsCollection)
            {
                Dependencies.Logger.RequiredAttributeOnCollection(navigation.ForeignKey.DependentToPrincipal);
                return;
            }

            if (!navigation.IsOnDependent)
            {
                var inverse = navigation.Inverse;
                if (inverse != null)
                {
                    var attributes = GetAttributes <RequiredAttribute>(inverse.DeclaringEntityType, inverse);
                    if (attributes.Any())
                    {
                        Dependencies.Logger.RequiredAttributeOnBothNavigations(navigation, inverse);
                        return;
                    }
                }

                if (relationshipBuilder.Metadata.GetPrincipalEndConfigurationSource() != null)
                {
                    Dependencies.Logger.RequiredAttributeOnDependent(navigation.ForeignKey.PrincipalToDependent);
                    return;
                }

                var newRelationshipBuilder = relationshipBuilder.HasEntityTypes(
                    relationshipBuilder.Metadata.DeclaringEntityType,
                    relationshipBuilder.Metadata.PrincipalEntityType);

                if (newRelationshipBuilder == null)
                {
                    return;
                }

                Dependencies.Logger.RequiredAttributeInverted(newRelationshipBuilder.Metadata.DependentToPrincipal);
                relationshipBuilder = newRelationshipBuilder;
            }

            relationshipBuilder.IsRequired(true, fromDataAnnotation: true);

            context.StopProcessingIfChanged(relationshipBuilder.Metadata.DependentToPrincipal);
        }
コード例 #2
0
        /// <summary>
        ///     Called after a navigation is added to the entity type.
        /// </summary>
        /// <param name="relationshipBuilder"> The builder for the foreign key. </param>
        /// <param name="navigation"> The navigation. </param>
        /// <param name="context"> Additional information associated with convention execution. </param>
        public virtual void ProcessNavigationAdded(
            IConventionRelationshipBuilder relationshipBuilder,
            IConventionNavigation navigation,
            IConventionContext <IConventionNavigation> context)
        {
            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));
            Check.NotNull(navigation, nameof(navigation));

            var modelBuilder = relationshipBuilder.ModelBuilder;

            if (!IsNonNullable(modelBuilder, navigation) ||
                navigation.IsCollection())
            {
                return;
            }

            if (!navigation.IsDependentToPrincipal())
            {
                var inverse = navigation.FindInverse();
                if (inverse != null)
                {
                    if (IsNonNullable(modelBuilder, inverse))
                    {
                        Dependencies.Logger.NonNullableReferenceOnBothNavigations(navigation, inverse);
                        return;
                    }
                }

                if (!navigation.ForeignKey.IsUnique ||
                    relationshipBuilder.Metadata.GetPrincipalEndConfigurationSource() != null)
                {
                    Dependencies.Logger.NonNullableReferenceOnDependent(navigation.ForeignKey.PrincipalToDependent);
                    return;
                }

                var newRelationshipBuilder = relationshipBuilder.HasEntityTypes(
                    relationshipBuilder.Metadata.DeclaringEntityType,
                    relationshipBuilder.Metadata.PrincipalEntityType);

                if (newRelationshipBuilder == null)
                {
                    return;
                }

                Dependencies.Logger.NonNullableInverted(newRelationshipBuilder.Metadata.DependentToPrincipal);
                relationshipBuilder = newRelationshipBuilder;
            }

            relationshipBuilder.IsRequired(true);

            context.StopProcessingIfChanged(relationshipBuilder.Metadata.DependentToPrincipal);
        }
        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(((ForeignKey)foreignKey).Builder.ReuniquifyTemporaryProperties(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
                    ? ((ForeignKey)foreignKey).Builder.ReuniquifyTemporaryProperties(true)
                    : relationshipBuilder);
            }

            if (conflictingFKCount > 0)
            {
                return(((ForeignKey)foreignKey).Builder.ReuniquifyTemporaryProperties(false));
            }

            var newRelationshipBuilder = relationshipBuilder.HasForeignKey(foreignKeyProperties);

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

            return(relationshipBuilder.Metadata.Builder == null ? null : relationshipBuilder);
        }