/// <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); }
/// <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)));
/// <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; }
/// <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); }
/// <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); }
/// <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)));
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); }
/// <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);
InternalRelationshipBuilder IForeignKeyUniquenessChangedConvention.Apply(InternalRelationshipBuilder relationshipBuilder) => DiscoverProperties(relationshipBuilder);
/// <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); }
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)) { }
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); }
/// <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); }
/// <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; }