public void Can_finding_targets_for_same_hierarchy_foreign_keys() { var fk = CreateOneToManySameHierarchyFK(); Assert.Same(fk.PrincipalEntityType, fk.ResolveOtherEntityType(fk.DeclaringEntityType)); Assert.Same(fk.DeclaringEntityType, fk.ResolveOtherEntityType(fk.PrincipalEntityType)); Assert.Same(fk.PrincipalToDependent, fk.FindNavigationsFrom(fk.PrincipalEntityType).SingleOrDefault()); Assert.Same(fk.DependentToPrincipal, fk.FindNavigationsFrom(fk.DeclaringEntityType).SingleOrDefault()); Assert.Same(fk.DependentToPrincipal, fk.FindNavigationsTo(fk.PrincipalEntityType).SingleOrDefault()); Assert.Same(fk.PrincipalToDependent, fk.FindNavigationsTo(fk.DeclaringEntityType).SingleOrDefault()); Assert.Equal( CoreStrings.IntraHierarchicalAmbiguousTargetEntityType(fk.DeclaringEntityType.DisplayName(), Property.Format(fk.Properties), fk.PrincipalEntityType.DisplayName(), fk.DeclaringEntityType.DisplayName()), Assert.Throws <InvalidOperationException>(() => fk.ResolveEntityTypeInHierarchy(fk.DeclaringEntityType)).Message); Assert.Equal( CoreStrings.IntraHierarchicalAmbiguousTargetEntityType(fk.PrincipalEntityType.DisplayName(), Property.Format(fk.Properties), fk.PrincipalEntityType.DisplayName(), fk.DeclaringEntityType.DisplayName()), Assert.Throws <InvalidOperationException>(() => fk.ResolveEntityTypeInHierarchy(fk.PrincipalEntityType)).Message); Assert.Equal( CoreStrings.IntraHierarchicalAmbiguousTargetEntityType(fk.DeclaringEntityType.DisplayName(), Property.Format(fk.Properties), fk.PrincipalEntityType.DisplayName(), fk.DeclaringEntityType.DisplayName()), Assert.Throws <InvalidOperationException>(() => fk.ResolveOtherEntityTypeInHierarchy(fk.DeclaringEntityType)).Message); Assert.Equal( CoreStrings.IntraHierarchicalAmbiguousTargetEntityType(fk.PrincipalEntityType.DisplayName(), Property.Format(fk.Properties), fk.PrincipalEntityType.DisplayName(), fk.DeclaringEntityType.DisplayName()), Assert.Throws <InvalidOperationException>(() => fk.ResolveOtherEntityTypeInHierarchy(fk.PrincipalEntityType)).Message); Assert.Equal( new[] { fk.PrincipalToDependent, fk.DependentToPrincipal }.Where(n => n != null), fk.FindNavigationsFromInHierarchy(fk.PrincipalEntityType)); Assert.Equal( new[] { fk.PrincipalToDependent, fk.DependentToPrincipal }.Where(n => n != null), fk.FindNavigationsFromInHierarchy(fk.DeclaringEntityType)); Assert.Equal( new[] { fk.PrincipalToDependent, fk.DependentToPrincipal }.Where(n => n != null), fk.FindNavigationsToInHierarchy(fk.PrincipalEntityType)); Assert.Equal( new[] { fk.PrincipalToDependent, fk.DependentToPrincipal }.Where(n => n != null), fk.FindNavigationsToInHierarchy(fk.DeclaringEntityType)); }
/// <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 bool AreCompatible([NotNull] this IForeignKey foreignKey, [NotNull] IForeignKey duplicateForeignKey, bool shouldThrow) { var principalAnnotations = foreignKey.PrincipalEntityType.Relational(); var duplicatePrincipalAnnotations = duplicateForeignKey.PrincipalEntityType.Relational(); if (!string.Equals(principalAnnotations.Schema, duplicatePrincipalAnnotations.Schema, StringComparison.OrdinalIgnoreCase) || !string.Equals(principalAnnotations.TableName, duplicatePrincipalAnnotations.TableName, StringComparison.OrdinalIgnoreCase)) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateForeignKeyPrincipalTableMismatch( Property.Format(foreignKey.Properties), foreignKey.DeclaringEntityType.DisplayName(), Property.Format(duplicateForeignKey.Properties), duplicateForeignKey.DeclaringEntityType.DisplayName(), Format(foreignKey.DeclaringEntityType.Relational()), foreignKey.Relational().Name, Format(principalAnnotations), Format(duplicatePrincipalAnnotations))); } return(false); } if (!foreignKey.Properties.Select(p => p.Relational().ColumnName) .SequenceEqual(duplicateForeignKey.Properties.Select(p => p.Relational().ColumnName))) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateForeignKeyColumnMismatch( Property.Format(foreignKey.Properties), foreignKey.DeclaringEntityType.DisplayName(), Property.Format(duplicateForeignKey.Properties), duplicateForeignKey.DeclaringEntityType.DisplayName(), Format(foreignKey.DeclaringEntityType.Relational()), foreignKey.Relational().Name, foreignKey.Properties.FormatColumns(), duplicateForeignKey.Properties.FormatColumns())); } return(false); } if (!foreignKey.PrincipalKey.Properties .Select(p => p.Relational().ColumnName) .SequenceEqual( duplicateForeignKey.PrincipalKey.Properties .Select(p => p.Relational().ColumnName))) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateForeignKeyPrincipalColumnMismatch( Property.Format(foreignKey.Properties), foreignKey.DeclaringEntityType.DisplayName(), Property.Format(duplicateForeignKey.Properties), duplicateForeignKey.DeclaringEntityType.DisplayName(), Format(foreignKey.DeclaringEntityType.Relational()), foreignKey.Relational().Name, foreignKey.PrincipalKey.Properties.FormatColumns(), duplicateForeignKey.PrincipalKey.Properties.FormatColumns())); } return(false); } if (foreignKey.IsUnique != duplicateForeignKey.IsUnique) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateForeignKeyUniquenessMismatch( Property.Format(foreignKey.Properties), foreignKey.DeclaringEntityType.DisplayName(), Property.Format(duplicateForeignKey.Properties), duplicateForeignKey.DeclaringEntityType.DisplayName(), Format(foreignKey.DeclaringEntityType.Relational()), foreignKey.Relational().Name)); } return(false); } if (foreignKey.DeleteBehavior != duplicateForeignKey.DeleteBehavior) { if (shouldThrow) { throw new InvalidOperationException( RelationalStrings.DuplicateForeignKeyDeleteBehaviorMismatch( Property.Format(foreignKey.Properties), foreignKey.DeclaringEntityType.DisplayName(), Property.Format(duplicateForeignKey.Properties), duplicateForeignKey.DeclaringEntityType.DisplayName(), Format(foreignKey.DeclaringEntityType.Relational()), foreignKey.Relational().Name, foreignKey.DeleteBehavior, duplicateForeignKey.DeleteBehavior)); } return(false); } return(true); }
/// <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 bool AreCompatible( [NotNull] EntityType principalEntityType, [NotNull] EntityType dependentEntityType, [CanBeNull] PropertyInfo navigationToPrincipal, [CanBeNull] PropertyInfo navigationToDependent, [CanBeNull] IReadOnlyList <Property> dependentProperties, [CanBeNull] IReadOnlyList <Property> principalProperties, bool?unique, bool?required, bool shouldThrow) { Check.NotNull(principalEntityType, nameof(principalEntityType)); Check.NotNull(dependentEntityType, nameof(dependentEntityType)); if (principalEntityType.HasDelegatedIdentity() && principalEntityType.ClrType == dependentEntityType.ClrType) { if (shouldThrow) { throw new InvalidOperationException( CoreStrings.ForeignKeySelfReferencingDelegatedIdentity(dependentEntityType.DisplayName())); } return(false); } if (navigationToPrincipal != null && !Internal.Navigation.IsCompatible( navigationToPrincipal, dependentEntityType.ClrType, principalEntityType.ClrType, shouldBeCollection: false, shouldThrow: shouldThrow)) { return(false); } if (navigationToDependent != null && !Internal.Navigation.IsCompatible( navigationToDependent, principalEntityType.ClrType, dependentEntityType.ClrType, shouldBeCollection: !unique, shouldThrow: shouldThrow)) { return(false); } // FKs are not allowed to use properties from inherited keys since this could result in an ambiguous value space if (dependentProperties != null && dependentEntityType.BaseType != null) { var inheritedKey = dependentProperties.SelectMany(p => p.GetContainingKeys().Where(k => k.DeclaringEntityType != dependentEntityType)).FirstOrDefault(); if (inheritedKey != null) { if (shouldThrow) { throw new InvalidOperationException( CoreStrings.ForeignKeyPropertyInKey( dependentProperties.First(p => inheritedKey.Properties.Contains(p)).Name, dependentEntityType.DisplayName(), Property.Format(inheritedKey.Properties), inheritedKey.DeclaringEntityType.DisplayName())); } return(false); } } if (dependentProperties != null && !CanPropertiesBeRequired(dependentProperties, required, dependentEntityType, true)) { return(false); } if (principalProperties != null && dependentProperties != null && !AreCompatible( principalProperties, dependentProperties, principalEntityType, dependentEntityType, shouldThrow)) { return(false); } return(true); }