private 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 && (!targetEntityType.Model.ShouldBeOwnedType(targetEntityType.ClrType) || entityType.IsInOwnershipPath(targetEntityType))) || relationshipCandidate.InverseProperties.Count > 1 || isAmbiguousOnBase || HasDeclaredAmbiguousNavigationsTo(entityType, targetEntityType.ClrType) || HasDeclaredAmbiguousNavigationsTo(targetEntityType, entityType.ClrType)) { if (!isAmbiguousOnBase) { AddAmbiguous(entityTypeBuilder, relationshipCandidate.NavigationProperties, targetEntityType.ClrType); AddAmbiguous(targetEntityType.Builder, relationshipCandidate.InverseProperties, entityType.ClrType); _logger.MultipleNavigationProperties( relationshipCandidate.NavigationProperties.Count == 0 ? new[] { new Tuple <MemberInfo, Type>(null, targetEntityType.ClrType) } : relationshipCandidate.NavigationProperties.Select(n => new Tuple <MemberInfo, Type>(n, entityType.ClrType)), relationshipCandidate.InverseProperties.Count == 0 ? new[] { new Tuple <MemberInfo, Type>(null, targetEntityType.ClrType) } : relationshipCandidate.InverseProperties.Select(n => new Tuple <MemberInfo, Type>(n, targetEntityType.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 && !targetEntityType.Model.ShouldBeOwnedType(targetEntityType.ClrType)) { continue; } if (InversePropertyAttributeConvention.IsAmbiguous(entityType, navigation, targetEntityType)) { unusedEntityTypes.Add(targetEntityType); continue; } var inverse = relationshipCandidate.InverseProperties.SingleOrDefault(); if (inverse == null) { if (targetEntityType.Model.ShouldBeOwnedType(targetEntityType.ClrType) && !entityType.IsInOwnershipPath(targetEntityType)) { 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.Model.ShouldBeOwnedType(targetEntityType.ClrType) && !entityType.IsInOwnershipPath(targetEntityType)) { 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 InternalRelationshipBuilder ConfigureInverseNavigation( InternalEntityTypeBuilder entityTypeBuilder, MemberInfo navigationMemberInfo, InternalEntityTypeBuilder targetEntityTypeBuilder, InversePropertyAttribute attribute) { var entityType = entityTypeBuilder.Metadata; var targetClrType = targetEntityTypeBuilder.Metadata.ClrType; var inverseNavigationPropertyInfo = targetEntityTypeBuilder.Metadata.GetRuntimeProperties().Values .FirstOrDefault(p => string.Equals(p.Name, attribute.Property, StringComparison.OrdinalIgnoreCase)); if (inverseNavigationPropertyInfo == null || !FindCandidateNavigationPropertyType(inverseNavigationPropertyInfo).GetTypeInfo() .IsAssignableFrom(entityType.ClrType.GetTypeInfo())) { throw new InvalidOperationException( CoreStrings.InvalidNavigationWithInverseProperty( navigationMemberInfo.Name, entityType.DisplayName(), attribute.Property, targetClrType.ShortDisplayName())); } if (Equals(inverseNavigationPropertyInfo, navigationMemberInfo)) { throw new InvalidOperationException( CoreStrings.SelfReferencingNavigationWithInverseProperty( navigationMemberInfo.Name, entityType.DisplayName(), navigationMemberInfo.Name, entityType.DisplayName())); } // Check for InversePropertyAttribute on the inverseNavigation to verify that it matches. if (Attribute.IsDefined(inverseNavigationPropertyInfo, typeof(InversePropertyAttribute))) { var inverseAttribute = inverseNavigationPropertyInfo.GetCustomAttribute <InversePropertyAttribute>(true); if (inverseAttribute.Property != navigationMemberInfo.Name) { throw new InvalidOperationException( CoreStrings.InversePropertyMismatch( navigationMemberInfo.Name, entityType.DisplayName(), inverseNavigationPropertyInfo.Name, targetEntityTypeBuilder.Metadata.DisplayName())); } } var referencingNavigationsWithAttribute = AddInverseNavigation(entityType, navigationMemberInfo, targetEntityTypeBuilder.Metadata, inverseNavigationPropertyInfo); if (IsAmbiguousInverse(navigationMemberInfo, entityType.ClrType, entityType.Model, referencingNavigationsWithAttribute)) { var existingInverse = targetEntityTypeBuilder.Metadata.FindNavigation(inverseNavigationPropertyInfo)?.FindInverse(); var existingInverseType = existingInverse?.DeclaringEntityType.ClrType; if (existingInverse != null && IsAmbiguousInverse( existingInverse.GetIdentifyingMemberInfo(), existingInverseType, entityType.Model, referencingNavigationsWithAttribute)) { var fk = existingInverse.ForeignKey; fk.DeclaringEntityType.Builder.RemoveForeignKey(fk, ConfigurationSource.DataAnnotation); } var existingRelationship = entityTypeBuilder.Metadata.FindNavigation(navigationMemberInfo)?.ForeignKey; existingRelationship?.DeclaringEntityType.Builder.RemoveForeignKey(existingRelationship, ConfigurationSource.DataAnnotation); return(entityTypeBuilder.Metadata.FindNavigation(navigationMemberInfo)?.ForeignKey.Builder); } var ownership = entityType.FindOwnership(); if (ownership != null && ownership.PrincipalEntityType == targetEntityTypeBuilder.Metadata && ownership.PrincipalToDependent?.GetIdentifyingMemberInfo() != inverseNavigationPropertyInfo) { _logger.NonOwnershipInverseNavigationWarning(entityType, navigationMemberInfo, targetEntityTypeBuilder.Metadata, inverseNavigationPropertyInfo, ownership.PrincipalToDependent.GetIdentifyingMemberInfo()); return(null); } if (entityType.DefiningEntityType == targetEntityTypeBuilder.Metadata && entityType.DefiningNavigationName != inverseNavigationPropertyInfo.Name) { _logger.NonDefiningInverseNavigationWarning(entityType, navigationMemberInfo, targetEntityTypeBuilder.Metadata, inverseNavigationPropertyInfo, targetEntityTypeBuilder.Metadata.GetRuntimeProperties()[entityType.DefiningNavigationName]); return(null); } if (entityType.Model.ShouldBeOwnedType(entityType.ClrType) && !entityType.IsInOwnershipPath(targetEntityTypeBuilder.Metadata)) { return(targetEntityTypeBuilder.Owns( entityTypeBuilder.Metadata.ClrType, inverseNavigationPropertyInfo, navigationMemberInfo, ConfigurationSource.Convention)); } return(targetEntityTypeBuilder.Relationship( entityTypeBuilder, inverseNavigationPropertyInfo, navigationMemberInfo, ConfigurationSource.DataAnnotation)); }