/// <summary> /// Adds a new relationship to this entity. /// </summary> /// <param name="properties"> The properties that the foreign key is defined on. </param> /// <param name="principalKey"> The primary or alternate key that is referenced. </param> /// <param name="principalEntity"> /// The entity type that the relationship targets. This may be different from the type that <paramref name="principalKey" /> /// is defined on when the relationship targets a derived type in an inheritance hierarchy (since the key is defined on the /// base type of the hierarchy). /// </param> /// <returns> The newly created foreign key. </returns> internal ForeignKey AddForeignKey(IReadOnlyList <Property> properties, Key principalKey, Entity principalEntity, bool runConventions = true) { Check.NotEmpty(properties, nameof(properties)); Check.HasNoNulls(properties, nameof(properties)); Check.NotNull(principalKey, nameof(principalKey)); Check.NotNull(principalEntity, nameof(principalEntity)); foreach (var property in properties) { var actualProperty = FindProperty(property.Name); if (actualProperty == null || !actualProperty.DeclaringEntity.IsAssignableFrom(property.DeclaringEntity)) { throw new InvalidOperationException(ResX.ForeignKeyPropertiesWrongEntity(Property.Format(properties), Name)); } if (actualProperty.GetContainingKeys().Any(k => k.DeclaringEntity != this)) { throw new InvalidOperationException(ResX.ForeignKeyPropertyInKey(actualProperty.Name, Name)); } } var duplicateForeignKey = FindForeignKeysInHierarchy(properties, principalKey, principalEntity).FirstOrDefault(); if (duplicateForeignKey != null) { throw new InvalidOperationException(ResX.DuplicateForeignKey(Property.Format(properties), Name, duplicateForeignKey.DeclaringEntity.Name, Property.Format(principalKey.Properties), principalEntity.Name)); } var foreignKey = new ForeignKey(properties, principalKey, this, principalEntity); _foreignKeys.Add(foreignKey); foreach (var property in properties) { var currentKeys = property.ForeignKeys; if (currentKeys == null) { property.ForeignKeys = new ForeignKey[] { foreignKey }; } else { var newKeys = currentKeys.ToList(); newKeys.Add(foreignKey); property.ForeignKeys = newKeys; } } if (principalKey.ReferencingForeignKeys == null) { principalKey.ReferencingForeignKeys = new List <ForeignKey> { foreignKey }; } else { principalKey.ReferencingForeignKeys.Add(foreignKey); } if (principalEntity.DeclaredReferencingForeignKeys == null) { principalEntity.DeclaredReferencingForeignKeys = new List <ForeignKey> { foreignKey }; } else { principalEntity.DeclaredReferencingForeignKeys.Add(foreignKey); } if (runConventions) { Model.ConventionDispatcher.OnForeignKeyAdded(foreignKey); } return(foreignKey); }
public Navigation(PropertyInfo navigationProperty, ForeignKey fkToLinkedEntity, ForeignKey fkToTargetedEntity) : base(Check.NotNull(navigationProperty, nameof(navigationProperty)).Name, navigationProperty) { Check.NotNull(fkToLinkedEntity, nameof(fkToLinkedEntity)); Check.NotNull(fkToTargetedEntity, nameof(fkToTargetedEntity)); ForeignKeyToLinkedEntity = fkToLinkedEntity; ForeignKeyToTargetedEntity = fkToTargetedEntity; }
internal Navigation AddNavigation(PropertyInfo navigationProperty, ForeignKey fkToLinkedEntity, ForeignKey fkToTargetedEntity) { Check.NotNull(navigationProperty, nameof(navigationProperty)); Check.NotNull(fkToLinkedEntity, nameof(fkToLinkedEntity)); Check.NotNull(fkToTargetedEntity, nameof(fkToTargetedEntity)); var name = navigationProperty.Name; var duplicateNavigation = FindNavigationsInHierarchy(name).FirstOrDefault(); if (duplicateNavigation != null) { throw new InvalidOperationException(ResX.DuplicateNavigation(name, Name, duplicateNavigation.DeclaringEntity.Name)); } var duplicateProperty = FindPropertiesInHierarchy(name).FirstOrDefault(); if (duplicateProperty != null) { throw new InvalidOperationException(ResX.ConflictingProperty(name, Name, duplicateProperty.DeclaringEntity.Name)); } var navigation = new Navigation(navigationProperty, fkToLinkedEntity, fkToTargetedEntity); _navigations.Add(name, navigation); return(navigation); }
/// <summary> /// Gets the relational database specific metadata for a foreign key. /// </summary> /// <param name="foreignKey"> The foreign key to get metadata for. </param> /// <returns> The relational database specific metadata for the foreign key. </returns> public static IRelationalForeignKeyAnnotations Relational(this ForeignKey foreignKey) => new RelationalForeignKeyAnnotations(Check.NotNull(foreignKey, nameof(foreignKey)));