Beispiel #1
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 ForeignKey(
            [NotNull] IReadOnlyList<Property> dependentProperties,
            [NotNull] Key principalKey,
            [NotNull] EntityType dependentEntityType,
            [NotNull] EntityType principalEntityType,
            ConfigurationSource configurationSource)
        {
            Check.NotEmpty(dependentProperties, nameof(dependentProperties));
            Check.HasNoNulls(dependentProperties, nameof(dependentProperties));
            Check.NotNull(principalKey, nameof(principalKey));
            Check.NotNull(principalEntityType, nameof(principalEntityType));

            Properties = dependentProperties;
            PrincipalKey = principalKey;
            DeclaringEntityType = dependentEntityType;
            PrincipalEntityType = principalEntityType;
            _configurationSource = configurationSource;

            AreCompatible(principalKey.Properties, dependentProperties, principalEntityType, dependentEntityType, shouldThrow: true);

            if (!principalEntityType.GetKeys().Contains(principalKey))
            {
                throw new InvalidOperationException(
                    CoreStrings.ForeignKeyReferencedEntityKeyMismatch(
                        Property.Format(principalKey.Properties),
                        principalEntityType));
            }

            Builder = new InternalRelationshipBuilder(this, dependentEntityType.Model.Builder);
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            ConfigureValueGenerationStrategy(
                relationshipBuilder.ModelBuilder.Entity(relationshipBuilder.Metadata.EntityType.Name, ConfigurationSource.Convention),
                relationshipBuilder.Metadata.Properties,
                false);

            return relationshipBuilder;
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            relationshipBuilder.DeleteBehavior(
                ((IForeignKey)relationshipBuilder.Metadata).IsRequired
                    ? DeleteBehavior.Cascade
                    : DeleteBehavior.Restrict,
                ConfigurationSource.Convention);

            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;
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            foreach (var property in relationshipBuilder.Metadata.Properties)
            {
                var propertyBuilder = property.Builder;
                propertyBuilder.RequiresValueGenerator(false, ConfigurationSource.Convention);
                propertyBuilder.ValueGenerated(ValueGenerated.Never, ConfigurationSource.Convention);
            }

            return relationshipBuilder;
        }
        private bool ShouldFlip(InternalRelationshipBuilder relationshipBuilder, IReadOnlyList<Property> currentDependentCandidateProperties)
        {
            var foreignKey = relationshipBuilder.Metadata;
            var currentPrincipalCandidateProperties = FindCandidateForeignKeyProperties(relationshipBuilder, onDependent: false);

            if (currentDependentCandidateProperties != null
                && currentPrincipalCandidateProperties == null)
            {
                return false;
            }

            if (currentDependentCandidateProperties == null
                && currentPrincipalCandidateProperties != null)
            {
                return true;
            }

            var navigationToPrincipal = foreignKey.DependentToPrincipal;
            var navigationToDependent = foreignKey.PrincipalToDependent;

            if (navigationToPrincipal == null
                && navigationToDependent != null)
            {
                return false;
            }

            if (navigationToPrincipal != null
                && navigationToDependent == null)
            {
                return true;
            }

            var model = foreignKey.DeclaringEntityType.Model;
            var principalPk = foreignKey.PrincipalEntityType.FindPrimaryKey();
            var principalPkReferenceThreshold = foreignKey.PrincipalKey == principalPk ? 1 : 0;
            var isPrincipalKeyReferenced = principalPk != null && model.FindReferencingForeignKeys(principalPk).Count() > principalPkReferenceThreshold;
            var dependentPk = foreignKey.DeclaringEntityType.FindPrimaryKey();
            var isDependentPrimaryKeyReferenced = dependentPk != null && model.FindReferencingForeignKeys(dependentPk).Any();

            if (isPrincipalKeyReferenced
                && !isDependentPrimaryKeyReferenced)
            {
                return false;
            }

            if (!isPrincipalKeyReferenced
                && isDependentPrimaryKeyReferenced)
            {
                return true;
            }

            return StringComparer.Ordinal.Compare(foreignKey.PrincipalEntityType.Name, foreignKey.DeclaringEntityType.Name) > 0;
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            foreach (var property in relationshipBuilder.Metadata.Properties)
            {
                var propertyBuilder = relationshipBuilder.ModelBuilder
                    .Entity(property.DeclaringEntityType.Name, ConfigurationSource.Convention)
                    .Property(property.Name, ConfigurationSource.Convention);

                propertyBuilder.UseValueGenerator(false, ConfigurationSource.Convention);
                propertyBuilder.ValueGenerated(ValueGenerated.Never, ConfigurationSource.Convention);
            }

            return relationshipBuilder;
        }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = (IForeignKey)relationshipBuilder.Metadata;
            if (foreignKey.Properties.All(fk => fk.IsShadowProperty))
            {
                var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder, onDependent: true);

                if (foreignKey.IsUnique
                    && !foreignKey.IsSelfPrimaryKeyReferencing())
                {
                    if (ShouldFlip(relationshipBuilder, foreignKeyProperties))
                    {
                        var newRelationshipBuilder = relationshipBuilder.Invert(ConfigurationSource.Convention);
                        if (newRelationshipBuilder != null)
                        {
                            return newRelationshipBuilder;
                        }
                    }

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

                if (foreignKeyProperties != null
                    && relationshipBuilder.Metadata.DeclaringEntityType.FindForeignKey(foreignKeyProperties) == null)
                {
                    var newRelationshipBuilder = relationshipBuilder.ForeignKey(foreignKeyProperties, ConfigurationSource.Convention);
                    if (newRelationshipBuilder != null)
                    {
                        return newRelationshipBuilder;
                    }
                }
            }

            return relationshipBuilder;
        }
 public OnForeignKeyAddedNode(InternalRelationshipBuilder relationshipBuilder)
 {
     RelationshipBuilder = relationshipBuilder;
 }
 public virtual InternalRelationshipBuilder OnPrincipalEndChanged([NotNull] InternalRelationshipBuilder relationshipBuilder)
 {
     Add(new OnPrincipalEndChangedNode(relationshipBuilder));
     return(relationshipBuilder);
 }
 public virtual InternalRelationshipBuilder OnNavigationAdded(
     [NotNull] InternalRelationshipBuilder relationshipBuilder, [NotNull] Navigation navigation)
 {
     Add(new OnNavigationAddedNode(relationshipBuilder, navigation));
     return(relationshipBuilder);
 }
 public OnForeignKeyOwnershipChangedNode(InternalRelationshipBuilder relationshipBuilder)
 {
     RelationshipBuilder = relationshipBuilder;
 }
 public OnNavigationAddedNode(InternalRelationshipBuilder relationshipBuilder, Navigation navigation)
 {
     RelationshipBuilder = relationshipBuilder;
     Navigation          = navigation;
 }
        public virtual InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));

            var foreignKey = relationshipBuilder.Metadata;

            var fkPropertyOnPrincipal = FindCandidateDependentPropertyThroughEntityType(foreignKey.PrincipalEntityType, foreignKey.PrincipalToDependent?.Name);
            var fkPropertyOnDependent = FindCandidateDependentPropertyThroughEntityType(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
                var principalTypeNavigationName = foreignKey.PrincipalToDependent?.Name;
                var dependentTypeNavigationName = foreignKey.DependentToPrincipal?.Name;

                var dependentEntityTypebuilder = relationshipBuilder.ModelBuilder.Entity(foreignKey.DeclaringEntityType.Name, ConfigurationSource.Convention);
                var removedConfigurationSource = dependentEntityTypebuilder.RemoveRelationship(foreignKey, ConfigurationSource.DataAnnotation);

                if (removedConfigurationSource == null)
                {
                    return relationshipBuilder;
                }

                var principalEntityTypeBuilder = relationshipBuilder.ModelBuilder.Entity(foreignKey.PrincipalEntityType.Name, ConfigurationSource.Convention);

                dependentEntityTypebuilder.Relationship(
                    principalEntityTypeBuilder,
                    dependentEntityTypebuilder,
                    navigationToPrincipalName: dependentTypeNavigationName,
                    navigationToDependentName: null,
                    configurationSource: ConfigurationSource.DataAnnotation);

                principalEntityTypeBuilder.Relationship(
                    dependentEntityTypebuilder,
                    principalEntityTypeBuilder,
                    navigationToPrincipalName: principalTypeNavigationName,
                    navigationToDependentName: null,
                    configurationSource: ConfigurationSource.DataAnnotation);

                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 mismatch in foreignKey Attribute on both navigations
                return relationshipBuilder;
            }

            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.ForeignKey(new List<string> { fkPropertyOnDependent }, ConfigurationSource.DataAnnotation);
                }
                else
                {
                    newRelationshipBuilder = relationshipBuilder.Invert(ConfigurationSource.DataAnnotation)
                        ?.ForeignKey(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.ForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder.Invert(ConfigurationSource.DataAnnotation)
                            ?.ForeignKey(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
                        return relationshipBuilder;
                    }
                    if (fkPropertyOnDependent != null)
                    {
                        newRelationshipBuilder = relationshipBuilder.ForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                    else
                    {
                        newRelationshipBuilder = relationshipBuilder.Invert(ConfigurationSource.DataAnnotation)
                            ?.ForeignKey(fkPropertiesOnNavigation, ConfigurationSource.DataAnnotation);
                    }
                }
            }
            return newRelationshipBuilder ?? relationshipBuilder;
        }
 public static InternalRelationshipBuilder Run(
     [NotNull] this IConventionBatch batch, [NotNull] InternalRelationshipBuilder relationshipBuilder)
 => (InternalRelationshipBuilder)batch.Run(relationshipBuilder.Metadata)?.Builder;
        private void SplitNavigationsInSeparateRelationships(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = relationshipBuilder.Metadata;
            var dependentToPrincipalNavigationName = foreignKey.DependentToPrincipal?.Name;
            var principalToDepedentNavigationName = foreignKey.PrincipalToDependent?.Name;

            if ((GetInversePropertyAttributeOnNavigation(foreignKey.PrincipalToDependent) != null)
                || (GetInversePropertyAttributeOnNavigation(foreignKey.DependentToPrincipal) != null))
            {
                // Relationship is joined by InversePropertyAttribute
                throw new InvalidOperationException(CoreStrings.InvalidRelationshipUsingDataAnnotations(
                    dependentToPrincipalNavigationName,
                    foreignKey.DeclaringEntityType.Name,
                    principalToDepedentNavigationName,
                    foreignKey.PrincipalEntityType.Name));
            }

            var dependentEntityTypebuilder = foreignKey.DeclaringEntityType.Builder;
            var principalEntityTypeBuilder = foreignKey.PrincipalEntityType.Builder;

            dependentEntityTypebuilder.Relationship(
                principalEntityTypeBuilder,
                dependentToPrincipalNavigationName,
                null,
                ConfigurationSource.DataAnnotation);

            principalEntityTypeBuilder.Relationship(
                dependentEntityTypebuilder,
                principalToDepedentNavigationName,
                null,
                ConfigurationSource.DataAnnotation);
        }
 /// <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, Navigation navigation)
     => Apply(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 void OnPrincipalKeySet_calls_apply_on_conventions_in_order(bool useBuilder)
        {
            var conventions = new ConventionSet();

            InternalRelationshipBuilder relationshipBuilder = null;
            var convention = new Mock<IPrincipalEndConvention>();
            convention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.NotNull(b);
                    relationshipBuilder = new InternalRelationshipBuilder(b.Metadata, b.ModelBuilder);
                    return relationshipBuilder;
                });
            conventions.PrincipalEndSetConventions.Add(convention.Object);

            var nullConvention = new Mock<IPrincipalEndConvention>();
            nullConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.Same(relationshipBuilder, b);
                    return null;
                });
            conventions.PrincipalEndSetConventions.Add(nullConvention.Object);

            var extraConvention = new Mock<IPrincipalEndConvention>();
            extraConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.False(true);
                    return null;
                });
            conventions.PrincipalEndSetConventions.Add(extraConvention.Object);

            var modelBuilder = new InternalModelBuilder(new Model(conventions));

            var entityBuilder = modelBuilder.Entity(typeof(Order), ConfigurationSource.Convention);
            entityBuilder.PrimaryKey(new[] { "OrderId" }, ConfigurationSource.Convention);
            var dependentEntityBuilder = modelBuilder.Entity(typeof(OrderDetails), ConfigurationSource.Convention);

            if (useBuilder)
            {
                Assert.Null(
                    dependentEntityBuilder
                        .Relationship(entityBuilder, ConfigurationSource.Convention)
                        .HasPrincipalKey(entityBuilder.Metadata.FindPrimaryKey().Properties, ConfigurationSource.Convention));
            }
            else
            {
                Assert.Null(dependentEntityBuilder.Metadata.AddForeignKey(
                    dependentEntityBuilder.Property("Id", typeof(int), ConfigurationSource.Convention).Metadata,
                    entityBuilder.Metadata.FindPrimaryKey(),
                    entityBuilder.Metadata,
                    ConfigurationSource.Convention));
            }

            Assert.NotNull(relationshipBuilder);
        }
        private IReadOnlyList<string> FindCandidateDependentPropertiesThroughNavigation(InternalRelationshipBuilder relationshipBuilder, bool pointsToPrincipal)
        {
            var navigation = pointsToPrincipal
                ? relationshipBuilder.Metadata.DependentToPrincipal
                : relationshipBuilder.Metadata.PrincipalToDependent;

            var navigationFkAttribute = navigation != null
                ? GetForeignKeyAttribute(navigation.DeclaringEntityType, navigation.Name)
                : null;

            if (navigationFkAttribute != null)
            {
                var properties = navigationFkAttribute.Name.Split(',').Select(p => p.Trim()).ToList();

                if (properties.Any(string.IsNullOrWhiteSpace))
                {
                    throw new InvalidOperationException(CoreStrings.InvalidPropertyListOnNavigation(navigation.Name, navigation.DeclaringEntityType.Name));
                }

                return properties;
            }
            return null;
        }
        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;
        }
        private void SplitNavigationsInSeparateRelationships(InternalRelationshipBuilder relationshipBuilder)
        {
            var foreignKey = relationshipBuilder.Metadata;
            var dependentToPrincipalNavigationName = foreignKey.DependentToPrincipal?.Name;
            var principalToDepedentNavigationName = foreignKey.PrincipalToDependent?.Name;


            if (GetInversePropertyAttributeOnNavigation(foreignKey.PrincipalToDependent) != null
                || GetInversePropertyAttributeOnNavigation(foreignKey.DependentToPrincipal) != null)
            {
                // Relationship is joined by InversePropertyAttribute
                throw new InvalidOperationException(CoreStrings.InvalidRelationshipUsingDataAnnotations(
                    dependentToPrincipalNavigationName,
                    foreignKey.DeclaringEntityType.Name,
                    principalToDepedentNavigationName,
                    foreignKey.PrincipalEntityType.Name));
            }

            var dependentEntityTypebuilder = relationshipBuilder.ModelBuilder.Entity(foreignKey.DeclaringEntityType.Name, ConfigurationSource.Convention);
            var removedConfigurationSource = dependentEntityTypebuilder.RemoveForeignKey(foreignKey, ConfigurationSource.DataAnnotation);

            if (removedConfigurationSource == null)
            {
                // Relationship not removed
                return;
            }

            var principalEntityTypeBuilder = relationshipBuilder.ModelBuilder.Entity(foreignKey.PrincipalEntityType.Name, ConfigurationSource.Convention);

            dependentEntityTypebuilder.Relationship(
                principalEntityTypeBuilder,
                dependentEntityTypebuilder,
                navigationToPrincipalName: dependentToPrincipalNavigationName,
                navigationToDependentName: null,
                configurationSource: ConfigurationSource.DataAnnotation);

            principalEntityTypeBuilder.Relationship(
                dependentEntityTypebuilder,
                principalEntityTypeBuilder,
                navigationToPrincipalName: principalToDepedentNavigationName,
                navigationToDependentName: null,
                configurationSource: ConfigurationSource.DataAnnotation);
        }
Beispiel #23
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 OnNavigationAdded(
     [NotNull] InternalRelationshipBuilder relationshipBuilder, [NotNull] Navigation navigation)
 => _scope.OnNavigationAdded(
     Check.NotNull(relationshipBuilder, nameof(relationshipBuilder)),
     Check.NotNull(navigation, nameof(navigation)));
Beispiel #24
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 OnPrincipalEndChanged([NotNull] InternalRelationshipBuilder relationshipBuilder)
 => _scope.OnPrincipalEndChanged(Check.NotNull(relationshipBuilder, nameof(relationshipBuilder)));
        private IReadOnlyList<string> FindCandidateDependentPropertiesThroughNavigation(InternalRelationshipBuilder relationshipBuilder, bool pointsToPrincipal)
        {
            var navigation = pointsToPrincipal
                ? relationshipBuilder.Metadata.DependentToPrincipal
                : relationshipBuilder.Metadata.PrincipalToDependent;

            var navigationFkAttribute = navigation != null
                ? GetForeignKeyAttribute(navigation.DeclaringEntityType, navigation.Name)
                : null;

            if (navigationFkAttribute != null)
            {
                var properties = navigationFkAttribute.Name.Split(',').Select(p => p.Trim()).ToList();

                if (properties.Any(string.IsNullOrWhiteSpace))
                {
                    throw new InvalidOperationException(CoreStrings.InvalidPropertyListOnNavigation(navigation.Name, navigation.DeclaringEntityType.Name));
                }

                var navigationPropertyTargetType = navigation.DeclaringEntityType.ClrType.GetRuntimeProperties()
                    .Single(p => p.Name == navigation.Name).PropertyType;

                var otherNavigations = navigation.DeclaringEntityType.ClrType.GetRuntimeProperties()
                    .Where(p => p.PropertyType == navigationPropertyTargetType && p.Name != navigation.Name)
                    .OrderBy(p => p.Name);
                foreach (var propertyInfo in otherNavigations)
                {
                    var attribute = propertyInfo.GetCustomAttribute<ForeignKeyAttribute>(true);
                    if ((attribute != null)
                        && (attribute.Name == navigationFkAttribute.Name))
                    {
                        throw new InvalidOperationException(CoreStrings.MultipleNavigationsSameFk(navigation.DeclaringEntityType.DisplayName(), attribute.Name));
                    }
                }

                return properties;
            }
            return null;
        }
Beispiel #26
0
 /// <summary>
 ///     <para>
 ///         Initializes a new instance of the <see cref="CollectionReferenceBuilder{TEntity,TRelatedEntity}" /> class.
 ///     </para>
 ///     <para>
 ///         Instances of this class are returned from methods when using the <see cref="ModelBuilder" /> API
 ///         and it is not designed to be directly constructed in your application code.
 ///     </para>
 /// </summary>
 /// <param name="builder"> The internal builder being used to configure this relationship. </param>
 public CollectionReferenceBuilder([NotNull] InternalRelationshipBuilder builder)
     : base(builder)
 {
 }
        /// <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)
        {
            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;
            var upgradePrincipalToDependentNavigationSource = fkPropertiesOnPrincipalToDependent != null;
            var upgradeDependentToPrincipalNavigationSource = fkPropertiesOnDependentToPrincipal != null;
            ConfigurationSource? invertConfigurationSource = null;
            IReadOnlyList<string> fkPropertiesToSet;

            if ((fkPropertiesOnNavigation == null)
                || (fkPropertiesOnNavigation.Count == 0))
            {
                if ((fkPropertyOnDependent == null)
                    && (fkPropertyOnPrincipal == null))
                {
                    return relationshipBuilder;
                }
                if (fkPropertyOnDependent != null)
                {
                    fkPropertiesToSet = new List<string> { fkPropertyOnDependent };
                    upgradeDependentToPrincipalNavigationSource = true;
                }
                else
                {
                    invertConfigurationSource = ConfigurationSource.DataAnnotation;
                    fkPropertiesToSet = new List<string> { fkPropertyOnPrincipal };
                    upgradeDependentToPrincipalNavigationSource = true;
                }
            }
            else
            {
                fkPropertiesToSet = fkPropertiesOnNavigation;
                if ((fkPropertyOnDependent == null)
                    && (fkPropertyOnPrincipal == null))
                {
                    if (fkPropertiesOnPrincipalToDependent != null
                        && foreignKey.IsUnique)
                    {
                        invertConfigurationSource = 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)
                    {
                        upgradeDependentToPrincipalNavigationSource = true;
                    }
                    else
                    {
                        invertConfigurationSource = ConfigurationSource.DataAnnotation;
                    }
                }
            }

            var newRelationshipBuilder = relationshipBuilder;
            if (invertConfigurationSource != null)
            {
                newRelationshipBuilder = newRelationshipBuilder.RelatedEntityTypes(
                    foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, invertConfigurationSource.Value);
                if (newRelationshipBuilder != null)
                {
                    var temp = upgradeDependentToPrincipalNavigationSource;
                    upgradeDependentToPrincipalNavigationSource = upgradePrincipalToDependentNavigationSource;
                    upgradePrincipalToDependentNavigationSource = temp;
                }
            }
            if (newRelationshipBuilder != null
                && upgradeDependentToPrincipalNavigationSource)
            {
                newRelationshipBuilder = newRelationshipBuilder.DependentToPrincipal(
                    newRelationshipBuilder.Metadata.DependentToPrincipal.Name, ConfigurationSource.DataAnnotation);
            }
            if (newRelationshipBuilder != null
                && upgradePrincipalToDependentNavigationSource)
            {
                newRelationshipBuilder = newRelationshipBuilder.PrincipalToDependent(
                    newRelationshipBuilder.Metadata.PrincipalToDependent.Name, ConfigurationSource.DataAnnotation);
            }

            return newRelationshipBuilder?.HasForeignKey(fkPropertiesToSet, ConfigurationSource.DataAnnotation) ?? 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(
     [NotNull] InternalRelationshipBuilder relationshipBuilder,
     [NotNull] Navigation navigation,
     [NotNull] TAttribute attribute) => throw new NotImplementedException();
        public void OnForeignKeyAdded_calls_apply_on_conventions_in_order()
        {
            var conventions = new ConventionSet();

            InternalRelationshipBuilder relationshipBuilder = null;
            var convention = new Mock<IForeignKeyConvention>();
            convention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.NotNull(b);
                    relationshipBuilder = new InternalRelationshipBuilder(b.Metadata, b.ModelBuilder, null);
                    return relationshipBuilder;
                });
            conventions.ForeignKeyAddedConventions.Add(convention.Object);

            var nullConvention = new Mock<IForeignKeyConvention>();
            nullConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.Same(relationshipBuilder, b);
                    return null;
                });
            conventions.ForeignKeyAddedConventions.Add(nullConvention.Object);

            var extraConvention = new Mock<IForeignKeyConvention>();
            extraConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>())).Returns<InternalRelationshipBuilder>(b =>
                {
                    Assert.False(true);
                    return null;
                });
            conventions.ForeignKeyAddedConventions.Add(extraConvention.Object);

            var builder = new InternalModelBuilder(new Model(), conventions);

            var entityBuilder = builder.Entity(typeof(Order), ConfigurationSource.Convention);
            entityBuilder.PrimaryKey(new[] { "OrderId" }, ConfigurationSource.Convention);
            Assert.Null(entityBuilder.Relationship(typeof(Order), typeof(Order), null, null, ConfigurationSource.Convention));

            Assert.NotNull(relationshipBuilder);
        }
 public OnForeignKeyUniquenessChangedNode(InternalRelationshipBuilder relationshipBuilder)
 {
     RelationshipBuilder = relationshipBuilder;
 }
        public void OnNavigationAdded_calls_apply_on_conventions_in_order()
        {
            var conventions = new ConventionSet();

            InternalRelationshipBuilder relationshipBuilder = null;
            var orderIgnored = false;
            var orderDetailsIgnored = false;
            var convention = new Mock<INavigationConvention>();
            convention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.NotNull(b);
                    relationshipBuilder = new InternalRelationshipBuilder(b.Metadata, b.ModelBuilder, ConfigurationSource.Convention);
                    return relationshipBuilder;
                });
            conventions.NavigationAddedConventions.Add(convention.Object);

            var nullConvention = new Mock<INavigationConvention>();
            nullConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.Same(relationshipBuilder, b);
                    if (n.Name == "Order")
                    {
                        orderIgnored = true;
                    }
                    if (n.Name == "OrderDetails")
                    {
                        orderDetailsIgnored = true;
                    }
                    return null;
                });
            conventions.NavigationAddedConventions.Add(nullConvention.Object);

            var extraConvention = new Mock<INavigationConvention>();
            extraConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.False(true);
                    return null;
                });
            conventions.NavigationAddedConventions.Add(extraConvention.Object);

            var builder = new InternalModelBuilder(new Model(), conventions);

            var entityBuilder = builder.Entity(typeof(Order), ConfigurationSource.Convention);
            entityBuilder.PrimaryKey(new[] { "OrderId" }, ConfigurationSource.Convention);

            Assert.Null(entityBuilder.Relationship(typeof(Order), typeof(OrderDetails), "Order", "OrderDetails", ConfigurationSource.Convention, isUnique: true));

            Assert.True(orderIgnored);
            Assert.False(orderDetailsIgnored);
            Assert.NotNull(relationshipBuilder);
        }
 public OnPrincipalEndChangedNode(InternalRelationshipBuilder relationshipBuilder)
 {
     RelationshipBuilder = relationshipBuilder;
 }
        private IReadOnlyList<Property> FindCandidateForeignKeyProperties(InternalRelationshipBuilder relationshipBuilder, bool onDependent)
        {
            var foreignKey = relationshipBuilder.Metadata;
            var baseNames = new List<string>();
            var navigation = onDependent
                ? foreignKey.DependentToPrincipal
                : foreignKey.PrincipalToDependent;
            if (navigation != null)
            {
                baseNames.Add(navigation.Name);
            }

            var entityTypeToReference = onDependent
                ? foreignKey.PrincipalEntityType
                : foreignKey.DeclaringEntityType;
            baseNames.Add(entityTypeToReference.DisplayName());

            baseNames.Add("");

            foreach (var baseName in baseNames)
            {
                var match = FindMatchingNonShadowProperties(relationshipBuilder, baseName, onDependent);
                if (match != null)
                {
                    return match;
                }
            }

            return null;
        }
 public virtual InternalRelationshipBuilder OnForeignKeyOwnershipChanged([NotNull] InternalRelationshipBuilder relationshipBuilder)
 {
     Add(new OnForeignKeyOwnershipChangedNode(relationshipBuilder));
     return(relationshipBuilder);
 }
        private IReadOnlyList<Property> FindMatchingNonShadowProperties(InternalRelationshipBuilder relationshipBuilder, string baseName, bool onDependent)
        {
            var foreignKey = relationshipBuilder.Metadata;
            var entityType = onDependent
                ? foreignKey.DeclaringEntityType
                : foreignKey.PrincipalEntityType;
            var propertiesToReference = onDependent
                ? foreignKey.PrincipalKey.Properties
                : foreignKey.DeclaringEntityType.FindPrimaryKey()?.Properties;

            if (propertiesToReference == null)
            {
                return null;
            }

            var foreignKeyProperties = new List<Property>();
            foreach (IProperty referencedProperty in propertiesToReference)
            {
                var property = TryGetProperty(entityType,
                    baseName + referencedProperty.Name,
                    referencedProperty.ClrType.UnwrapNullableType());

                if (property != null)
                {
                    foreignKeyProperties.Add(property);
                }
            }

            if (propertiesToReference.Count == 1
                && foreignKeyProperties.Count == 0)
            {
                var property = TryGetProperty(entityType,
                    baseName + "Id",
                    ((IProperty)propertiesToReference.Single()).ClrType.UnwrapNullableType());

                if (property != null)
                {
                    foreignKeyProperties.Add(property);
                }
            }

            if (foreignKeyProperties.Count < propertiesToReference.Count)
            {
                return null;
            }
            
            if (!relationshipBuilder.CanSetForeignKey(foreignKeyProperties, ConfigurationSource.Convention))
            {
                return null;
            }

            var primaryKey = entityType.FindPrimaryKey();
            if (primaryKey != null)
            {
                if (foreignKeyProperties.All(property => primaryKey.Properties.Contains(property)))
                {
                    return null;
                }
            }

            return foreignKeyProperties;
        }
            public override InternalRelationshipBuilder OnForeignKeyUniquenessChanged(InternalRelationshipBuilder relationshipBuilder)
            {
                if (relationshipBuilder.Metadata.Builder == null)
                {
                    return(null);
                }

                foreach (var uniquenessConvention in _conventionSet.ForeignKeyUniquenessChangedConventions)
                {
                    relationshipBuilder = uniquenessConvention.Apply(relationshipBuilder);
                    if (relationshipBuilder?.Metadata.Builder == null)
                    {
                        return(null);
                    }
                }

                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);
            }
        }
        public void OnNavigationAdded_calls_apply_on_conventions_in_order(bool useBuilder)
        {
            var conventions = new ConventionSet();

            InternalRelationshipBuilder relationshipBuilder = null;
            var orderIgnored        = false;
            var orderDetailsIgnored = false;
            var convention          = new Mock <INavigationConvention>();

            convention.Setup(c => c.Apply(It.IsAny <InternalRelationshipBuilder>(), It.IsAny <Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
            {
                Assert.NotNull(b);
                relationshipBuilder = new InternalRelationshipBuilder(b.Metadata, b.ModelBuilder);
                return(relationshipBuilder);
            });
            conventions.NavigationAddedConventions.Add(convention.Object);

            var nullConvention = new Mock <INavigationConvention>();

            nullConvention.Setup(c => c.Apply(It.IsAny <InternalRelationshipBuilder>(), It.IsAny <Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
            {
                Assert.Same(relationshipBuilder, b);
                if (n.Name == "Order")
                {
                    orderIgnored = true;
                }
                if (n.Name == "OrderDetails")
                {
                    orderDetailsIgnored = true;
                }
                return(null);
            });
            conventions.NavigationAddedConventions.Add(nullConvention.Object);

            var extraConvention = new Mock <INavigationConvention>();

            extraConvention.Setup(c => c.Apply(It.IsAny <InternalRelationshipBuilder>(), It.IsAny <Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
            {
                Assert.False(true);
                return(null);
            });
            conventions.NavigationAddedConventions.Add(extraConvention.Object);

            var builder = new InternalModelBuilder(new Model(conventions));

            var principalEntityBuilder = builder.Entity(typeof(Order), ConfigurationSource.Convention);
            var dependentEntityBuilder = builder.Entity(typeof(OrderDetails), ConfigurationSource.Convention);

            if (useBuilder)
            {
                Assert.Null(dependentEntityBuilder.Relationship(principalEntityBuilder, nameof(OrderDetails.Order), nameof(Order.OrderDetails), ConfigurationSource.Convention));
            }
            else
            {
                var fk = dependentEntityBuilder.Relationship(principalEntityBuilder, ConfigurationSource.Convention)
                         .IsUnique(true, ConfigurationSource.Convention)
                         .Metadata;
                Assert.Null(fk.HasDependentToPrincipal(nameof(OrderDetails.Order)));
            }

            Assert.True(orderIgnored);
            Assert.False(orderDetailsIgnored);
            Assert.NotNull(relationshipBuilder);
        }
Beispiel #39
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)
        {
            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

                return(SplitNavigationsToSeparateRelationships(relationshipBuilder) ? null : relationshipBuilder);
            }

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

            if ((fkPropertiesOnDependentToPrincipal != null) &&
                (fkPropertiesOnPrincipalToDependent != null))
            {
                // TODO: Log error that foreign key properties are on both navigations

                return(SplitNavigationsToSeparateRelationships(relationshipBuilder) ? null : relationshipBuilder);
            }

            var fkPropertiesOnNavigation = fkPropertiesOnDependentToPrincipal ?? fkPropertiesOnPrincipalToDependent;
            var upgradePrincipalToDependentNavigationSource  = fkPropertiesOnPrincipalToDependent != null;
            var upgradeDependentToPrincipalNavigationSource  = fkPropertiesOnDependentToPrincipal != null;
            ConfigurationSource?   invertConfigurationSource = null;
            IReadOnlyList <string> fkPropertiesToSet;

            if ((fkPropertiesOnNavigation == null) ||
                (fkPropertiesOnNavigation.Count == 0))
            {
                if ((fkPropertyOnDependent == null) &&
                    (fkPropertyOnPrincipal == null))
                {
                    return(relationshipBuilder);
                }
                if (fkPropertyOnDependent != null)
                {
                    fkPropertiesToSet = new List <string> {
                        fkPropertyOnDependent
                    };
                    upgradeDependentToPrincipalNavigationSource = true;
                }
                else
                {
                    invertConfigurationSource = ConfigurationSource.DataAnnotation;
                    fkPropertiesToSet         = new List <string> {
                        fkPropertyOnPrincipal
                    };
                    upgradeDependentToPrincipalNavigationSource = true;
                }
            }
            else
            {
                fkPropertiesToSet = fkPropertiesOnNavigation;
                if ((fkPropertyOnDependent == null) &&
                    (fkPropertyOnPrincipal == null))
                {
                    if (fkPropertiesOnPrincipalToDependent != null &&
                        foreignKey.IsUnique)
                    {
                        invertConfigurationSource = 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

                        return(SplitNavigationsToSeparateRelationships(relationshipBuilder) ? null : relationshipBuilder);
                    }

                    if (fkPropertyOnDependent != null)
                    {
                        upgradeDependentToPrincipalNavigationSource = true;
                    }
                    else
                    {
                        invertConfigurationSource = ConfigurationSource.DataAnnotation;
                    }
                }
            }

            var newRelationshipBuilder = relationshipBuilder;

            if (invertConfigurationSource != null)
            {
                newRelationshipBuilder = newRelationshipBuilder.RelatedEntityTypes(
                    foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, invertConfigurationSource.Value);
                if (newRelationshipBuilder != null)
                {
                    var temp = upgradeDependentToPrincipalNavigationSource;
                    upgradeDependentToPrincipalNavigationSource = upgradePrincipalToDependentNavigationSource;
                    upgradePrincipalToDependentNavigationSource = temp;
                }
            }
            if (newRelationshipBuilder != null &&
                upgradeDependentToPrincipalNavigationSource)
            {
                newRelationshipBuilder = newRelationshipBuilder.DependentToPrincipal(
                    newRelationshipBuilder.Metadata.DependentToPrincipal.Name, ConfigurationSource.DataAnnotation);
            }
            if (newRelationshipBuilder != null &&
                upgradePrincipalToDependentNavigationSource)
            {
                newRelationshipBuilder = newRelationshipBuilder.PrincipalToDependent(
                    newRelationshipBuilder.Metadata.PrincipalToDependent.Name, ConfigurationSource.DataAnnotation);
            }

            return(newRelationshipBuilder?.HasForeignKey(fkPropertiesToSet, ConfigurationSource.DataAnnotation) ?? relationshipBuilder);
        }
Beispiel #40
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 OnForeignKeyOwnershipChanged([NotNull] InternalRelationshipBuilder relationshipBuilder)
 => _scope.OnForeignKeyOwnershipChanged(Check.NotNull(relationshipBuilder, nameof(relationshipBuilder)));
Beispiel #41
0
        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.ClrType.MakeNullable(!foreignKey.IsRequired),
                                        fkProperty.Name,
                                        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.HasEntityTypes(
                    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.HasEntityTypes(
                    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
                                                          .HasEntityTypes(foreignKey.DeclaringEntityType, foreignKey.PrincipalEntityType, ConfigurationSource.Convention);
                        var invertedFk = invertedRelationshipBuilder?.Metadata;
                        if (invertedFk?.IsSelfReferencing() == true)
                        {
                            invertedRelationshipBuilder = invertedRelationshipBuilder.HasNavigations(
                                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
                                                                      .HasEntityTypes(
                                        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);
        }
Beispiel #42
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 static RelationalForeignKeyBuilderAnnotations SqlServer(
     [NotNull] this InternalRelationshipBuilder builder,
     ConfigurationSource configurationSource)
 => new RelationalForeignKeyBuilderAnnotations(builder, configurationSource, SqlServerFullAnnotationNames.Instance);
Beispiel #43
0
 InternalRelationshipBuilder IForeignKeyUniquenessChangedConvention.Apply(InternalRelationshipBuilder relationshipBuilder)
 => DiscoverProperties(relationshipBuilder);
Beispiel #44
0
        /// <summary>
        ///     <para>
        ///         Initializes a new instance of the <see cref="ReferenceReferenceBuilder" /> class.
        ///     </para>
        ///     <para>
        ///         Instances of this class are returned from methods when using the <see cref="ModelBuilder" /> API
        ///         and it is not designed to be directly constructed in your application code.
        ///     </para>
        /// </summary>
        /// <param name="builder"> The internal builder being used to configure this relationship. </param>
        public ReferenceReferenceBuilder([NotNull] InternalRelationshipBuilder builder)
        {
            Check.NotNull(builder, nameof(builder));

            _builder = builder;
        }
        public void OnNavigationAdded_calls_apply_on_conventions_in_order(bool useBuilder)
        {
            var conventions = new ConventionSet();

            InternalRelationshipBuilder relationshipBuilder = null;
            var orderIgnored = false;
            var orderDetailsIgnored = false;
            var convention = new Mock<INavigationConvention>();
            convention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.NotNull(b);
                    relationshipBuilder = new InternalRelationshipBuilder(b.Metadata, b.ModelBuilder);
                    return relationshipBuilder;
                });
            conventions.NavigationAddedConventions.Add(convention.Object);

            var nullConvention = new Mock<INavigationConvention>();
            nullConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.Same(relationshipBuilder, b);
                    if (n.Name == "Order")
                    {
                        orderIgnored = true;
                    }
                    if (n.Name == "OrderDetails")
                    {
                        orderDetailsIgnored = true;
                    }
                    return null;
                });
            conventions.NavigationAddedConventions.Add(nullConvention.Object);

            var extraConvention = new Mock<INavigationConvention>();
            extraConvention.Setup(c => c.Apply(It.IsAny<InternalRelationshipBuilder>(), It.IsAny<Navigation>())).Returns((InternalRelationshipBuilder b, Navigation n) =>
                {
                    Assert.False(true);
                    return null;
                });
            conventions.NavigationAddedConventions.Add(extraConvention.Object);

            var builder = new InternalModelBuilder(new Model(conventions));

            var principalEntityBuilder = builder.Entity(typeof(Order), ConfigurationSource.Convention);
            var dependentEntityBuilder = builder.Entity(typeof(OrderDetails), ConfigurationSource.Convention);

            if (useBuilder)
            {
                Assert.Null(dependentEntityBuilder.Relationship(principalEntityBuilder, OrderDetails.OrderProperty, Order.OrderDetailsProperty, ConfigurationSource.Convention));
            }
            else
            {
                var fk = dependentEntityBuilder.Relationship(principalEntityBuilder, ConfigurationSource.Convention)
                    .IsUnique(true, ConfigurationSource.Convention)
                    .Metadata;
                Assert.Null(fk.HasDependentToPrincipal(OrderDetails.OrderProperty));
            }

            Assert.True(orderIgnored);
            Assert.False(orderDetailsIgnored);
            Assert.NotNull(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, Navigation navigation)
 => Apply(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);

                bool shouldInvert;
                if (ShouldFlip(relationshipBuilder.Metadata, foreignKeyProperties, candidatePropertiesOnPrincipal)
                    && relationshipBuilder.CanSet(relationshipBuilder.Metadata.DeclaringEntityType,
                        relationshipBuilder.Metadata.PrincipalEntityType,
                        null,
                        null,
                        /*dependentProperties:*/ candidatePropertiesOnPrincipal,
                        null,
                        null,
                        null,
                        null,
                        true,
                        ConfigurationSource.Convention,
                        out shouldInvert))
                {
                    Debug.Assert(shouldInvert);
                    var invertedBuilder = relationshipBuilder.Invert(ConfigurationSource.Convention);
                    Debug.Assert(invertedBuilder != null);

                    if (candidatePropertiesOnPrincipal == null)
                    {
                        return invertedBuilder;
                    }

                    // TODO: Remove, as this is redundant
                    invertedBuilder = invertedBuilder.ForeignKey(
                        candidatePropertiesOnPrincipal, ConfigurationSource.Convention);
                    Debug.Assert(invertedBuilder != null);
                    return invertedBuilder;
                }

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

            if (foreignKeyProperties != null
                && relationshipBuilder.Metadata.DeclaringEntityType.FindForeignKey(foreignKeyProperties) == null)
            {
                var newRelationshipBuilder = relationshipBuilder.ForeignKey(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>
 InternalRelationshipBuilder IForeignKeyUniquenessChangedConvention.Apply(InternalRelationshipBuilder relationshipBuilder)
 => ConfigurationSource.Convention.Overrides(relationshipBuilder.Metadata.GetForeignKeyPropertiesConfigurationSource())
         ? Apply(relationshipBuilder)
         : 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 RelationalForeignKeyBuilderAnnotations(
     [NotNull] InternalRelationshipBuilder internalBuilder,
     ConfigurationSource configurationSource)
     : base(new RelationalAnnotationsBuilder(internalBuilder, configurationSource))
 {
 }
Beispiel #50
0
        private IReadOnlyList <string> FindCandidateDependentPropertiesThroughNavigation(InternalRelationshipBuilder relationshipBuilder, bool pointsToPrincipal)
        {
            var navigation = pointsToPrincipal
                ? relationshipBuilder.Metadata.DependentToPrincipal
                : relationshipBuilder.Metadata.PrincipalToDependent;

            var navigationFkAttribute = navigation != null
                ? GetForeignKeyAttribute(navigation.DeclaringEntityType, navigation.Name)
                : null;

            if (navigationFkAttribute != null)
            {
                var properties = navigationFkAttribute.Name.Split(',').Select(p => p.Trim()).ToList();

                if (properties.Any(string.IsNullOrWhiteSpace))
                {
                    throw new InvalidOperationException(
                              CoreStrings.InvalidPropertyListOnNavigation(navigation.Name, navigation.DeclaringEntityType.DisplayName()));
                }

                var navigationPropertyTargetType = navigation.DeclaringEntityType.ClrType.GetRuntimeProperties()
                                                   .Single(p => p.Name == navigation.Name).PropertyType;

                var otherNavigations = navigation.DeclaringEntityType.ClrType.GetRuntimeProperties()
                                       .Where(p => p.PropertyType == navigationPropertyTargetType && p.Name != navigation.Name)
                                       .OrderBy(p => p.Name);
                foreach (var propertyInfo in otherNavigations)
                {
                    var attribute = propertyInfo.GetCustomAttribute <ForeignKeyAttribute>(true);
                    if ((attribute != null) &&
                        (attribute.Name == navigationFkAttribute.Name))
                    {
                        throw new InvalidOperationException(
                                  CoreStrings.MultipleNavigationsSameFk(navigation.DeclaringEntityType.DisplayName(), attribute.Name));
                    }
                }

                return(properties);
            }
            return(null);
        }
Beispiel #51
0
        /// <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>
        InternalRelationshipBuilder IForeignKeyOwnershipChangedConvention.Apply(InternalRelationshipBuilder relationshipBuilder)
        {
            Apply(relationshipBuilder.Metadata.DeclaringEntityType.Builder);

            return(relationshipBuilder);
        }
Beispiel #52
0
 /// <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 InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder, Navigation navigation)
 => DiscoverProperties(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, Navigation navigation)
        {
            Apply(navigation);

            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>
 InternalRelationshipBuilder IForeignKeyUniquenessConvention.Apply(InternalRelationshipBuilder relationshipBuilder)
 => Apply(relationshipBuilder);
 public virtual bool Apply(InternalRelationshipBuilder relationshipBuilder, string navigationName, bool pointsToPrincipal)
 {
     var owner = pointsToPrincipal
         ? relationshipBuilder.Metadata.DeclaringEntityType
         : relationshipBuilder.Metadata.PrincipalEntityType;
     return Apply(relationshipBuilder.ModelBuilder.Entity(owner.Name, ConfigurationSource.Convention)) != null;
 }