public void InversePropertyAttribute_does_not_override_configuration_from_explicit_source()
        {
            var dependentEntityTypeBuilder = CreateInternalEntityTypeBuilder <Dependent>();
            var principalEntityTypeBuilder = dependentEntityTypeBuilder.ModelBuilder.Entity(typeof(Principal), ConfigurationSource.Convention);

            dependentEntityTypeBuilder.Relationship(
                principalEntityTypeBuilder,
                nameof(Dependent.Principal),
                nameof(Principal.Dependents),
                ConfigurationSource.Explicit);

            Assert.Contains(principalEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Principal.Dependents));
            Assert.DoesNotContain(principalEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Principal.Dependent));
            Assert.Contains(dependentEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Dependent.Principal));

            var convention = new InversePropertyAttributeConvention(CreateTypeMapper(), CreateLogger());

            new InversePropertyAttributeConvention(CreateTypeMapper(), CreateLogger()).Apply(dependentEntityTypeBuilder);

            Assert.Contains(principalEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Principal.Dependents));
            Assert.DoesNotContain(principalEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Principal.Dependent));
            Assert.Contains(dependentEntityTypeBuilder.Metadata.GetNavigations(), nav => nav.Name == nameof(Dependent.Principal));

            convention.Apply(dependentEntityTypeBuilder.ModelBuilder);
        }
        public void InversePropertyAttribute_does_not_configure_ambiguous_navigations()
        {
            var dependentEntityTypeBuilder = CreateInternalEntityTypeBuilder <AmbiguousDependent>();
            var principalEntityTypeBuilder = dependentEntityTypeBuilder.ModelBuilder.Entity(typeof(AmbiguousPrincipal), ConfigurationSource.Convention);

            dependentEntityTypeBuilder.Relationship(
                principalEntityTypeBuilder,
                nameof(AmbiguousDependent.AmbiguousPrincipal),
                nameof(AmbiguousPrincipal.Dependent),
                ConfigurationSource.Convention);

            Assert.Contains(principalEntityTypeBuilder.Metadata.GetNavigations(),
                            nav => nav.Name == nameof(AmbiguousPrincipal.Dependent));
            Assert.Contains(dependentEntityTypeBuilder.Metadata.GetNavigations(),
                            nav => nav.Name == nameof(AmbiguousDependent.AmbiguousPrincipal));
            Assert.DoesNotContain(dependentEntityTypeBuilder.Metadata.GetNavigations(),
                                  nav => nav.Name == nameof(AmbiguousDependent.AnotherAmbiguousPrincipal));

            var convention = new InversePropertyAttributeConvention(CreateTypeMapper(), CreateLogger());

            convention.Apply(dependentEntityTypeBuilder);

            Assert.DoesNotContain(principalEntityTypeBuilder.Metadata.GetNavigations(),
                                  nav => nav.Name == nameof(AmbiguousPrincipal.Dependent));
            Assert.DoesNotContain(dependentEntityTypeBuilder.Metadata.GetNavigations(),
                                  nav => nav.Name == nameof(AmbiguousDependent.AnotherAmbiguousPrincipal));
            Assert.DoesNotContain(dependentEntityTypeBuilder.Metadata.GetNavigations(),
                                  nav => nav.Name == nameof(AmbiguousDependent.AmbiguousPrincipal));

            convention.Apply(dependentEntityTypeBuilder.ModelBuilder);

            Assert.Equal(1, Log.Count);
            Assert.Equal(LogLevel.Information, Log[0].Level);
            Assert.Equal(CoreStrings.LogMultipleInversePropertiesSameTarget.GenerateMessage(
                             "AmbiguousDependent.AmbiguousPrincipal, AmbiguousDependent.AnotherAmbiguousPrincipal",
                             nameof(AmbiguousPrincipal.Dependent)), Log[0].Message);
        }
        private void CreateRelationships(
            IReadOnlyList <RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder)
        {
            var unusedEntityTypes = new List <EntityType>();

            foreach (var relationshipCandidate in relationshipCandidates)
            {
                Debug.Assert(relationshipCandidate.NavigationProperties.Count > 0);

                var entityType        = entityTypeBuilder.Metadata;
                var targetEntityType  = relationshipCandidate.TargetTypeBuilder.Metadata;
                var isAmbiguousOnBase = (entityType.BaseType != null &&
                                         HasAmbiguousNavigationsTo(
                                             entityType.BaseType, targetEntityType.ClrType)) ||
                                        (targetEntityType.BaseType != null &&
                                         HasAmbiguousNavigationsTo(
                                             targetEntityType.BaseType, entityType.ClrType));

                if ((relationshipCandidate.NavigationProperties.Count > 1 &&
                     relationshipCandidate.InverseProperties.Count > 0) ||
                    relationshipCandidate.InverseProperties.Count > 1 ||
                    isAmbiguousOnBase)
                {
                    if (!isAmbiguousOnBase)
                    {
                        AddAmbiguous(entityTypeBuilder, relationshipCandidate.NavigationProperties, targetEntityType.ClrType);

                        AddAmbiguous(relationshipCandidate.TargetTypeBuilder, relationshipCandidate.InverseProperties, entityType.ClrType);
                    }

                    foreach (var navigationProperty in relationshipCandidate.NavigationProperties)
                    {
                        var existingForeignKey = entityType.FindDeclaredNavigation(navigationProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    foreach (var inverseProperty in relationshipCandidate.InverseProperties)
                    {
                        var existingForeignKey = targetEntityType.FindDeclaredNavigation(inverseProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    unusedEntityTypes.Add(targetEntityType);

                    continue;
                }

                foreach (var navigation in relationshipCandidate.NavigationProperties)
                {
                    if (targetEntityType.Builder == null)
                    {
                        continue;
                    }

                    if (InversePropertyAttributeConvention.IsAmbiguous(entityType, navigation, targetEntityType))
                    {
                        unusedEntityTypes.Add(targetEntityType);
                        continue;
                    }

                    var inverse = relationshipCandidate.InverseProperties.SingleOrDefault();
                    if (inverse == null)
                    {
                        entityTypeBuilder.Navigation(
                            relationshipCandidate.TargetTypeBuilder,
                            navigation,
                            ConfigurationSource.Convention);
                    }
                    else
                    {
                        if (InversePropertyAttributeConvention.IsAmbiguous(targetEntityType, inverse, entityType))
                        {
                            unusedEntityTypes.Add(targetEntityType);
                            continue;
                        }
                        entityTypeBuilder.Relationship(
                            targetEntityType.Builder,
                            navigation,
                            inverse,
                            ConfigurationSource.Convention);
                    }
                }
            }

            foreach (var unusedEntityType in unusedEntityTypes)
            {
                if (unusedEntityType.HasDelegatedIdentity() &&
                    unusedEntityType.DefiningEntityType.FindNavigation(unusedEntityType.DefiningNavigationName) == null)
                {
                    entityTypeBuilder.ModelBuilder.
                    RemoveDelegatedIdentityEntityType(unusedEntityType, ConfigurationSource.Convention);
                }
            }
        }
        /// <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 ConventionSet CreateConventionSet(DiagnosticsLoggers loggers)
        {
            var conventionSet = new ConventionSet();
            var logger        = loggers.GetLogger <DbLoggerCategory.Model>();

            var propertyDiscoveryConvention
                = new PropertyDiscoveryConvention(
                      Dependencies.TypeMappingSource, logger);

            var keyDiscoveryConvention
                = new KeyDiscoveryConvention(logger);

            var inversePropertyAttributeConvention
                = new InversePropertyAttributeConvention(Dependencies.MemberClassifier, logger);

            var relationshipDiscoveryConvention
                = new RelationshipDiscoveryConvention(Dependencies.MemberClassifier, logger);

            var servicePropertyDiscoveryConvention
                = new ServicePropertyDiscoveryConvention(Dependencies.TypeMappingSource, Dependencies.ParameterBindingFactories, logger);

            conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new OwnedEntityTypeAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(new BaseTypeDiscoveryConvention(logger));
            conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeAddedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(new DerivedTypeDiscoveryConvention(logger));

            conventionSet.EntityTypeIgnoredConventions.Add(inversePropertyAttributeConvention);

            conventionSet.EntityTypeRemovedConventions.Add(new OwnedTypesConvention(logger));

            var foreignKeyIndexConvention = new ForeignKeyIndexConvention(logger);
            var valueGeneratorConvention  = new ValueGeneratorConvention(logger);

            conventionSet.BaseEntityTypeChangedConventions.Add(propertyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(foreignKeyIndexConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(valueGeneratorConvention);

            var foreignKeyPropertyDiscoveryConvention = new ForeignKeyPropertyDiscoveryConvention(logger);

            conventionSet.EntityTypeMemberIgnoredConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(relationshipDiscoveryConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(servicePropertyDiscoveryConvention);

            var keyAttributeConvention = new KeyAttributeConvention(logger);
            var backingFieldConvention = new BackingFieldConvention(logger);
            var concurrencyCheckAttributeConvention  = new ConcurrencyCheckAttributeConvention(logger);
            var databaseGeneratedAttributeConvention = new DatabaseGeneratedAttributeConvention(logger);
            var requiredPropertyAttributeConvention  = new RequiredPropertyAttributeConvention(logger);
            var maxLengthAttributeConvention         = new MaxLengthAttributeConvention(logger);
            var stringLengthAttributeConvention      = new StringLengthAttributeConvention(logger);
            var timestampAttributeConvention         = new TimestampAttributeConvention(logger);

            conventionSet.PropertyAddedConventions.Add(backingFieldConvention);
            conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(keyAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PrimaryKeyChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PrimaryKeyChangedConventions.Add(valueGeneratorConvention);

            conventionSet.KeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.KeyRemovedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyRemovedConventions.Add(foreignKeyIndexConvention);
            conventionSet.KeyRemovedConventions.Add(keyDiscoveryConvention);

            var cascadeDeleteConvention       = new CascadeDeleteConvention(logger);
            var foreignKeyAttributeConvention = new ForeignKeyAttributeConvention(Dependencies.MemberClassifier, logger);

            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyAttributeConvention);
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyAddedConventions.Add(cascadeDeleteConvention);
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyRemovedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyUniquenessChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyRequirednessChangedConventions.Add(cascadeDeleteConvention);
            conventionSet.ForeignKeyRequirednessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.ForeignKeyOwnershipChangedConventions.Add(new NavigationEagerLoadingConvention(logger));
            conventionSet.ForeignKeyOwnershipChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyOwnershipChangedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.ModelBuiltConventions.Add(new ModelCleanupConvention(logger));
            conventionSet.ModelBuiltConventions.Add(keyAttributeConvention);
            conventionSet.ModelBuiltConventions.Add(foreignKeyAttributeConvention);
            conventionSet.ModelBuiltConventions.Add(new ChangeTrackingStrategyConvention(logger));
            conventionSet.ModelBuiltConventions.Add(new ConstructorBindingConvention(Dependencies.ConstructorBindingFactory, logger));
            conventionSet.ModelBuiltConventions.Add(new TypeMappingConvention(Dependencies.TypeMappingSource, logger));
            conventionSet.ModelBuiltConventions.Add(new IgnoredMembersValidationConvention(logger));
            conventionSet.ModelBuiltConventions.Add(foreignKeyIndexConvention);

            conventionSet.ModelBuiltConventions.Add(
                new PropertyMappingValidationConvention(
                    Dependencies.TypeMappingSource,
                    Dependencies.MemberClassifier,
                    logger));

            conventionSet.ModelBuiltConventions.Add(new RelationshipValidationConvention(logger));
            conventionSet.ModelBuiltConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ModelBuiltConventions.Add(servicePropertyDiscoveryConvention);
            conventionSet.ModelBuiltConventions.Add(new CacheCleanupConvention(logger));

            conventionSet.NavigationAddedConventions.Add(backingFieldConvention);
            conventionSet.NavigationAddedConventions.Add(new RequiredNavigationAttributeConvention(logger));
            conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.NavigationAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.PrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PropertyNullabilityChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PropertyFieldChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(keyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(timestampAttributeConvention);

            return(conventionSet);
        }
        /// <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 ConventionSet CreateConventionSet()
        {
            var conventionSet = new ConventionSet();

            var propertyDiscoveryConvention        = new PropertyDiscoveryConvention(Dependencies.TypeMapper);
            var keyDiscoveryConvention             = new KeyDiscoveryConvention();
            var inversePropertyAttributeConvention = new InversePropertyAttributeConvention(Dependencies.TypeMapper);
            var relationshipDiscoveryConvention    = new RelationshipDiscoveryConvention(Dependencies.TypeMapper);

            conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention());
            conventionSet.EntityTypeAddedConventions.Add(new OwnedEntityTypeAttributeConvention());
            conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention());
            conventionSet.EntityTypeAddedConventions.Add(new BaseTypeDiscoveryConvention());
            conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeAddedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.EntityTypeAddedConventions.Add(new DerivedTypeDiscoveryConvention());
            conventionSet.EntityTypeIgnoredConventions.Add(inversePropertyAttributeConvention);

            var foreignKeyIndexConvention = new ForeignKeyIndexConvention();
            var valueGeneratorConvention  = new ValueGeneratorConvention();

            conventionSet.BaseEntityTypeChangedConventions.Add(propertyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(relationshipDiscoveryConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(foreignKeyIndexConvention);
            conventionSet.BaseEntityTypeChangedConventions.Add(valueGeneratorConvention);

            // An ambiguity might have been resolved
            conventionSet.EntityTypeMemberIgnoredConventions.Add(inversePropertyAttributeConvention);
            conventionSet.EntityTypeMemberIgnoredConventions.Add(relationshipDiscoveryConvention);

            var keyAttributeConvention = new KeyAttributeConvention();
            var foreignKeyPropertyDiscoveryConvention = new ForeignKeyPropertyDiscoveryConvention();
            var backingFieldConvention = new BackingFieldConvention();
            var concurrencyCheckAttributeConvention  = new ConcurrencyCheckAttributeConvention();
            var databaseGeneratedAttributeConvention = new DatabaseGeneratedAttributeConvention();
            var requiredPropertyAttributeConvention  = new RequiredPropertyAttributeConvention();
            var maxLengthAttributeConvention         = new MaxLengthAttributeConvention();
            var stringLengthAttributeConvention      = new StringLengthAttributeConvention();
            var timestampAttributeConvention         = new TimestampAttributeConvention();

            conventionSet.PropertyAddedConventions.Add(backingFieldConvention);
            conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention);
            conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PropertyAddedConventions.Add(keyAttributeConvention);

            conventionSet.PrimaryKeyChangedConventions.Add(valueGeneratorConvention);

            conventionSet.KeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.KeyRemovedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.KeyRemovedConventions.Add(foreignKeyIndexConvention);
            conventionSet.KeyRemovedConventions.Add(keyDiscoveryConvention);

            var cascadeDeleteConvention = new CascadeDeleteConvention();

            conventionSet.ForeignKeyAddedConventions.Add(new ForeignKeyAttributeConvention(Dependencies.TypeMapper));
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyAddedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyAddedConventions.Add(cascadeDeleteConvention);
            conventionSet.ForeignKeyAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyRemovedConventions.Add(keyDiscoveryConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(valueGeneratorConvention);
            conventionSet.ForeignKeyRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.ForeignKeyOwnershipChangedConventions.Add(new NavigationEagerLoadingConvention());

            conventionSet.ModelBuiltConventions.Add(new ModelCleanupConvention());
            conventionSet.ModelBuiltConventions.Add(keyAttributeConvention);
            conventionSet.ModelBuiltConventions.Add(new IgnoredMembersValidationConvention());
            conventionSet.ModelBuiltConventions.Add(new PropertyMappingValidationConvention(Dependencies.TypeMapper));
            conventionSet.ModelBuiltConventions.Add(new RelationshipValidationConvention());
            conventionSet.ModelBuiltConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.ModelBuiltConventions.Add(new ChangeTrackingStrategyConvention());
            conventionSet.ModelBuiltConventions.Add(new ConstructorBindingConvention(Dependencies.ConstructorBindingFactory));

            conventionSet.NavigationAddedConventions.Add(backingFieldConvention);
            conventionSet.NavigationAddedConventions.Add(new RequiredNavigationAttributeConvention());
            conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention);
            conventionSet.NavigationAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);

            conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexRemovedConventions.Add(foreignKeyIndexConvention);

            conventionSet.IndexUniquenessChangedConventions.Add(foreignKeyIndexConvention);

            conventionSet.PropertyNullabilityChangedConventions.Add(cascadeDeleteConvention);

            conventionSet.PrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);

            conventionSet.PropertyFieldChangedConventions.Add(keyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);
            conventionSet.PropertyFieldChangedConventions.Add(keyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(concurrencyCheckAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(databaseGeneratedAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(requiredPropertyAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(maxLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(stringLengthAttributeConvention);
            conventionSet.PropertyFieldChangedConventions.Add(timestampAttributeConvention);

            return(conventionSet);
        }
Ejemplo n.º 6
0
        private static void CreateRelationships(
            IEnumerable <RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder)
        {
            var unusedEntityTypes = new List <EntityType>();

            foreach (var relationshipCandidate in relationshipCandidates)
            {
                var entityType        = entityTypeBuilder.Metadata;
                var targetEntityType  = relationshipCandidate.TargetTypeBuilder.Metadata;
                var isAmbiguousOnBase = entityType.BaseType != null &&
                                        HasAmbiguousNavigationsTo(
                    entityType.BaseType, targetEntityType.ClrType) ||
                                        targetEntityType.BaseType != null &&
                                        HasAmbiguousNavigationsTo(
                    targetEntityType.BaseType, entityType.ClrType);

                if (relationshipCandidate.NavigationProperties.Count > 1 &&
                    relationshipCandidate.InverseProperties.Count > 0 ||
                    relationshipCandidate.InverseProperties.Count > 1 ||
                    isAmbiguousOnBase)
                {
                    if (!isAmbiguousOnBase)
                    {
                        AddAmbiguous(entityTypeBuilder, relationshipCandidate.NavigationProperties, targetEntityType.ClrType);

                        AddAmbiguous(targetEntityType.Builder, relationshipCandidate.InverseProperties, entityType.ClrType);
                    }

                    foreach (var navigationProperty in relationshipCandidate.NavigationProperties)
                    {
                        var existingForeignKey = entityType.FindDeclaredNavigation(navigationProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    foreach (var inverseProperty in relationshipCandidate.InverseProperties)
                    {
                        var existingForeignKey = targetEntityType.FindDeclaredNavigation(inverseProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    unusedEntityTypes.Add(targetEntityType);

                    continue;
                }

                foreach (var navigation in relationshipCandidate.NavigationProperties)
                {
                    if (targetEntityType.Builder == null)
                    {
                        continue;
                    }

                    if (InversePropertyAttributeConvention.IsAmbiguous(entityType, navigation, targetEntityType))
                    {
                        unusedEntityTypes.Add(targetEntityType);
                        continue;
                    }

                    var inverse = relationshipCandidate.InverseProperties.SingleOrDefault();
                    if (inverse == null)
                    {
                        if (targetEntityType.DefiningNavigationName == navigation.Name &&
                            targetEntityType.DefiningEntityType == entityType &&
                            targetEntityType.Model.ShouldBeOwnedType(targetEntityType.ClrType))
                        {
                            entityTypeBuilder.Owns(
                                targetEntityType.ClrType,
                                navigation,
                                ConfigurationSource.Convention);
                        }
                        else
                        {
                            entityTypeBuilder.Navigation(
                                targetEntityType.Builder,
                                navigation,
                                ConfigurationSource.Convention);
                        }
                    }
                    else
                    {
                        if (InversePropertyAttributeConvention.IsAmbiguous(targetEntityType, inverse, entityType))
                        {
                            unusedEntityTypes.Add(targetEntityType);
                            continue;
                        }

                        if (targetEntityType.DefiningNavigationName == navigation.Name &&
                            targetEntityType.DefiningEntityType == entityType &&
                            targetEntityType.Model.ShouldBeOwnedType(targetEntityType.ClrType))
                        {
                            entityTypeBuilder.Owns(
                                targetEntityType.ClrType,
                                navigation,
                                inverse,
                                ConfigurationSource.Convention);
                        }
                        else
                        {
                            entityTypeBuilder.Relationship(
                                targetEntityType.Builder,
                                navigation,
                                inverse,
                                ConfigurationSource.Convention);
                        }
                    }
                }

                if (relationshipCandidate.NavigationProperties.Count == 0)
                {
                    foreach (var inverse in relationshipCandidate.InverseProperties)
                    {
                        if (targetEntityType.Builder == null)
                        {
                            continue;
                        }

                        if (InversePropertyAttributeConvention.IsAmbiguous(targetEntityType, inverse, entityType))
                        {
                            unusedEntityTypes.Add(targetEntityType);
                            continue;
                        }

                        targetEntityType.Builder.Navigation(
                            entityTypeBuilder,
                            inverse,
                            ConfigurationSource.Convention);
                    }
                }
            }

            foreach (var unusedEntityType in unusedEntityTypes)
            {
                if (unusedEntityType.HasDefiningNavigation() &&
                    unusedEntityType.DefiningEntityType.FindNavigation(unusedEntityType.DefiningNavigationName) == null)
                {
                    entityTypeBuilder.ModelBuilder.RemoveEntityType(unusedEntityType, ConfigurationSource.Convention);
                }
            }
        }
        private void CreateRelationships(
            IReadOnlyList <RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder)
        {
            foreach (var relationshipCandidate in relationshipCandidates)
            {
                Debug.Assert(relationshipCandidate.NavigationProperties.Count > 0);
                var isAmbiguousOnBase = (entityTypeBuilder.Metadata.BaseType != null &&
                                         HasAmbiguousNavigationsTo(
                                             entityTypeBuilder.Metadata.BaseType, relationshipCandidate.TargetTypeBuilder.Metadata.ClrType)) ||
                                        (relationshipCandidate.TargetTypeBuilder.Metadata.BaseType != null &&
                                         HasAmbiguousNavigationsTo(
                                             relationshipCandidate.TargetTypeBuilder.Metadata.BaseType, entityTypeBuilder.Metadata.ClrType));

                if ((relationshipCandidate.NavigationProperties.Count > 1 &&
                     relationshipCandidate.InverseProperties.Count > 0) ||
                    relationshipCandidate.InverseProperties.Count > 1 ||
                    isAmbiguousOnBase)
                {
                    if (!isAmbiguousOnBase)
                    {
                        AddAmbiguous(entityTypeBuilder, relationshipCandidate.NavigationProperties, relationshipCandidate.TargetTypeBuilder.Metadata.ClrType);

                        AddAmbiguous(relationshipCandidate.TargetTypeBuilder, relationshipCandidate.InverseProperties, entityTypeBuilder.Metadata.ClrType);
                    }

                    foreach (var navigationProperty in relationshipCandidate.NavigationProperties)
                    {
                        var existingForeignKey = entityTypeBuilder.Metadata.FindDeclaredNavigation(navigationProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    foreach (var inverseProperty in relationshipCandidate.InverseProperties)
                    {
                        var existingForeignKey = relationshipCandidate.TargetTypeBuilder.Metadata
                                                 .FindDeclaredNavigation(inverseProperty.Name)?.ForeignKey;
                        existingForeignKey?.DeclaringEntityType.Builder
                        .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention);
                    }

                    continue;
                }

                foreach (var navigation in relationshipCandidate.NavigationProperties)
                {
                    if (InversePropertyAttributeConvention.IsAmbiguous(
                            entityTypeBuilder.Metadata, navigation, relationshipCandidate.TargetTypeBuilder.Metadata))
                    {
                        continue;
                    }
                    var inverse = relationshipCandidate.InverseProperties.SingleOrDefault();
                    if (inverse == null)
                    {
                        entityTypeBuilder.Navigation(
                            relationshipCandidate.TargetTypeBuilder,
                            navigation,
                            ConfigurationSource.Convention);
                    }
                    else
                    {
                        if (InversePropertyAttributeConvention.IsAmbiguous(
                                relationshipCandidate.TargetTypeBuilder.Metadata, inverse, entityTypeBuilder.Metadata))
                        {
                            continue;
                        }
                        entityTypeBuilder.Relationship(
                            relationshipCandidate.TargetTypeBuilder,
                            navigation,
                            inverse,
                            ConfigurationSource.Convention);
                    }
                }
            }
        }