private static void TryBuildRelationship( [NotNull] InternalEntityTypeBuilder sourceBuilder, [NotNull] InternalEntityTypeBuilder targetBuilder, [NotNull] PropertyInfo navigationToTarget, [CanBeNull] PropertyInfo navigationToSource) { var isToTargetNavigationCollection = navigationToTarget.PropertyType.TryGetSequenceType() != null; if (isToTargetNavigationCollection) { if (navigationToSource?.PropertyType.TryGetSequenceType() != null) { // TODO: Support many to many return; } targetBuilder.Relationship( sourceBuilder, targetBuilder, navigationToSource?.Name, navigationToTarget.Name, configurationSource: ConfigurationSource.Convention, isUnique: false, strictPrincipal: true); } else { if (navigationToSource == null) { targetBuilder.Relationship( targetBuilder, sourceBuilder, navigationToTarget.Name, navigationToDependentName: null, configurationSource: ConfigurationSource.Convention, isUnique: null, strictPrincipal: false); } else { if (navigationToSource.PropertyType.TryGetSequenceType() == null) { targetBuilder.Relationship( sourceBuilder, targetBuilder, navigationToSource.Name, navigationToTarget.Name, configurationSource: ConfigurationSource.Convention, isUnique: true, strictPrincipal: false); } } } }
private static void CreateRelationships( IReadOnlyList <RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder) { foreach (var relationshipCandidate in relationshipCandidates) { Debug.Assert(relationshipCandidate.NavigationProperties.Count > 0); if ((relationshipCandidate.NavigationProperties.Count > 1 && relationshipCandidate.InverseProperties.Count > 0) || relationshipCandidate.InverseProperties.Count > 1) { 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) { var inverse = relationshipCandidate.InverseProperties.SingleOrDefault(); if (inverse == null) { entityTypeBuilder.Navigation( relationshipCandidate.TargetTypeBuilder, navigation, ConfigurationSource.Convention); } else { entityTypeBuilder.Relationship( relationshipCandidate.TargetTypeBuilder, navigation, inverse, ConfigurationSource.Convention); } } } }
private void CreateRelationships( IReadOnlyList <RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder) { foreach (var relationshipCandidate in relationshipCandidates) { if ((relationshipCandidate.NavigationProperties.Count > 1 && relationshipCandidate.InverseProperties.Count > 0) || relationshipCandidate.InverseProperties.Count > 1) { foreach (var navigationProperty in relationshipCandidate.NavigationProperties) { var existingForeignKey = entityTypeBuilder.Metadata.FindDeclaredNavigation(navigationProperty.Name)?.ForeignKey; if (existingForeignKey != null) { entityTypeBuilder.ModelBuilder.Entity(existingForeignKey.DeclaringEntityType.Name, ConfigurationSource.Convention) .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention); } } foreach (var inverseProperty in relationshipCandidate.InverseProperties) { var existingForeignKey = relationshipCandidate.TargetTypeBuilder.Metadata.FindDeclaredNavigation(inverseProperty.Name)?.ForeignKey; if (existingForeignKey != null) { entityTypeBuilder.ModelBuilder.Entity(existingForeignKey.DeclaringEntityType.Name, ConfigurationSource.Convention) .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention); } } break; } foreach (var navigation in relationshipCandidate.NavigationProperties) { var inverse = relationshipCandidate.InverseProperties.SingleOrDefault(); entityTypeBuilder.Relationship( relationshipCandidate.TargetTypeBuilder, navigation, inverse, ConfigurationSource.Convention); } } }
private InternalRelationshipBuilder ConfigureInverseNavigation( InternalEntityTypeBuilder entityTypeBuilder, PropertyInfo navigationPropertyInfo, InternalEntityTypeBuilder targetEntityTypeBuilder, InversePropertyAttribute attribute) { var entityType = entityTypeBuilder.Metadata; var targetClrType = targetEntityTypeBuilder.Metadata.ClrType; var inverseNavigationPropertyInfo = targetClrType.GetRuntimeProperties().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( navigationPropertyInfo.Name, entityType.DisplayName(), attribute.Property, targetClrType.ShortDisplayName())); } if (Equals(inverseNavigationPropertyInfo, navigationPropertyInfo)) { throw new InvalidOperationException( CoreStrings.SelfReferencingNavigationWithInverseProperty( navigationPropertyInfo.Name, entityType.DisplayName(), navigationPropertyInfo.Name, entityType.DisplayName())); } // Check for InversePropertyAttribute on the inverseNavigation to verify that it matches. var inverseAttribute = inverseNavigationPropertyInfo.GetCustomAttribute <InversePropertyAttribute>(true); if (inverseAttribute != null && inverseAttribute.Property != navigationPropertyInfo.Name) { throw new InvalidOperationException( CoreStrings.InversePropertyMismatch( navigationPropertyInfo.Name, entityType.DisplayName(), inverseNavigationPropertyInfo.Name, targetEntityTypeBuilder.Metadata.DisplayName())); } var referencingNavigationsWithAttribute = AddInverseNavigation(entityType, navigationPropertyInfo, targetEntityTypeBuilder.Metadata, inverseNavigationPropertyInfo); if (IsAmbiguousInverse(navigationPropertyInfo, entityType.ClrType, entityType.Model, referencingNavigationsWithAttribute)) { var existingInverse = targetEntityTypeBuilder.Metadata.FindNavigation(inverseNavigationPropertyInfo)?.FindInverse(); var existingInverseType = existingInverse?.DeclaringEntityType.ClrType; if (existingInverse != null && IsAmbiguousInverse( existingInverse.MemberInfo, existingInverseType, entityType.Model, referencingNavigationsWithAttribute)) { var fk = existingInverse.ForeignKey; if (fk.GetConfigurationSource() == ConfigurationSource.DataAnnotation) { fk.DeclaringEntityType.Builder.RemoveForeignKey(fk, ConfigurationSource.DataAnnotation); } } return(entityTypeBuilder.Metadata.FindNavigation(navigationPropertyInfo)?.ForeignKey.Builder); } return(targetEntityTypeBuilder.Relationship( entityTypeBuilder, inverseNavigationPropertyInfo, navigationPropertyInfo, ConfigurationSource.DataAnnotation)); }
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); } } }
private InternalRelationshipBuilder ConfigureInverseNavigation( InternalEntityTypeBuilder entityTypeBuilder, MemberInfo navigationMemberInfo, InternalEntityTypeBuilder targetEntityTypeBuilder, InversePropertyAttribute attribute) { var entityType = entityTypeBuilder.Metadata; var targetClrType = targetEntityTypeBuilder.Metadata.ClrType; var inverseNavigationPropertyInfo = targetClrType.GetRuntimeProperties().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. var inverseAttribute = inverseNavigationPropertyInfo.GetCustomAttribute <InversePropertyAttribute>(true); if (inverseAttribute != null && 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, targetClrType.GetRuntimeProperties().First(p => p.Name == 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)); }
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) { var inverse = relationshipCandidate.InverseProperties.SingleOrDefault(); if (inverse == null) { entityTypeBuilder.Navigation( relationshipCandidate.TargetTypeBuilder, navigation, ConfigurationSource.Convention); } else { entityTypeBuilder.Relationship( relationshipCandidate.TargetTypeBuilder, navigation, inverse, ConfigurationSource.Convention); } } } }
private void CreateRelationships( IReadOnlyList<RelationshipCandidate> relationshipCandidates, InternalEntityTypeBuilder entityTypeBuilder) { foreach (var relationshipCandidate in relationshipCandidates) { if ((relationshipCandidate.NavigationProperties.Count > 1 && relationshipCandidate.InverseProperties.Count > 0) || relationshipCandidate.InverseProperties.Count > 1) { foreach (var navigationProperty in relationshipCandidate.NavigationProperties) { var existingForeignKey = entityTypeBuilder.Metadata.FindDeclaredNavigation(navigationProperty.Name)?.ForeignKey; if (existingForeignKey != null) { entityTypeBuilder.ModelBuilder.Entity(existingForeignKey.DeclaringEntityType.Name, ConfigurationSource.Convention) .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention); } } foreach (var inverseProperty in relationshipCandidate.InverseProperties) { var existingForeignKey = relationshipCandidate.TargetTypeBuilder.Metadata.FindDeclaredNavigation(inverseProperty.Name)?.ForeignKey; if (existingForeignKey != null) { entityTypeBuilder.ModelBuilder.Entity(existingForeignKey.DeclaringEntityType.Name, ConfigurationSource.Convention) .RemoveForeignKey(existingForeignKey, ConfigurationSource.Convention); } } break; } foreach (var navigation in relationshipCandidate.NavigationProperties) { var inverse = relationshipCandidate.InverseProperties.SingleOrDefault(); entityTypeBuilder.Relationship( relationshipCandidate.TargetTypeBuilder, navigation, inverse, ConfigurationSource.Convention); } } }