public void Configure_should_split_key_constraint_when_to_table_configuration() { var database = new DbDatabaseMetadata().Initialize(); var sourceTable = database.AddTable("Source"); var fkColumn = sourceTable.AddColumn("Fk"); var foreignKeyConstraint = new DbForeignKeyConstraintMetadata(); foreignKeyConstraint.DependentColumns.Add(fkColumn); sourceTable.ForeignKeyConstraints.Add(foreignKeyConstraint); var targetTable = database.AddTable("Split"); var associationSetMapping = new DbAssociationSetMapping().Initialize(); associationSetMapping.Table = sourceTable; associationSetMapping.SourceEndMapping.PropertyMappings.Add(new DbEdmPropertyMapping { Column = fkColumn }); var independentAssociationMappingConfiguration = new ForeignKeyAssociationMappingConfiguration(); independentAssociationMappingConfiguration.ToTable("Split"); independentAssociationMappingConfiguration.Configure(associationSetMapping, database); Assert.True(targetTable.Columns.Contains(fkColumn)); Assert.True(targetTable.ForeignKeyConstraints.Contains(foreignKeyConstraint)); Assert.False(sourceTable.Columns.Contains(fkColumn)); Assert.False(sourceTable.ForeignKeyConstraints.Contains(foreignKeyConstraint)); Assert.Same(targetTable, associationSetMapping.Table); }
internal void WriteForeignKeyConstraintElement( DbTableMetadata dbTableMetadata, DbForeignKeyConstraintMetadata tableFKConstraint) { _xmlWriter.WriteStartElement(SsdlConstants.Element_Association); _xmlWriter.WriteAttributeString(SsdlConstants.Attribute_Name, tableFKConstraint.Name); var multiplicity = DetermineMultiplicity(dbTableMetadata, tableFKConstraint); // If the FK is a Self Ref, then we need to append a suffix to the second role name var roleNames = DbModelSsdlHelper.GetRoleNamePair(tableFKConstraint.PrincipalTable, dbTableMetadata); // End WriteAssociationEndElementHeader(roleNames[0], tableFKConstraint.PrincipalTable, multiplicity.Key); if (tableFKConstraint.DeleteAction != DbOperationAction.None) { WriteOperationActionElement(SsdlConstants.Element_OnDelete, tableFKConstraint.DeleteAction); } WriteEndElement(); WriteAssociationEndElementHeader(roleNames[1], dbTableMetadata, multiplicity.Value); WriteEndElement(); // ReferentialConstraint WriteReferentialConstraintElementHeader(); WriteReferentialConstraintRoleElement( SsdlConstants.Element_PrincipalRole, roleNames[0], tableFKConstraint.PrincipalTable.KeyColumns); WriteReferentialConstraintRoleElement( SsdlConstants.Element_DependentRole, roleNames[1], tableFKConstraint.DependentColumns); WriteEndElement(); WriteEndElement(); }
public void Apply_should_introduce_cascade_delete_on_constraints() { var databaseMapping = new DbDatabaseMapping() .Initialize(new EdmModel().Initialize(), new DbDatabaseMetadata().Initialize()); var foreignKeyConstraint = new DbForeignKeyConstraintMetadata(); Assert.Equal(DbOperationAction.None, foreignKeyConstraint.DeleteAction); var table = new DbTableMetadata(); table.ForeignKeyConstraints.Add(foreignKeyConstraint); var associationType = new EdmAssociationType().Initialize(); associationType.SourceEnd.EndKind = EdmAssociationEndKind.Many; associationType.SourceEnd.EntityType = new EdmEntityType(); associationType.TargetEnd.EndKind = EdmAssociationEndKind.Many; associationType.TargetEnd.EntityType = new EdmEntityType(); var associationSetMapping = databaseMapping.AddAssociationSetMapping(new EdmAssociationSet { ElementType = associationType }); associationSetMapping.Table = table; ((IDbMappingConvention)new ManyToManyCascadeDeleteConvention()).Apply(databaseMapping); Assert.Equal(DbOperationAction.Cascade, foreignKeyConstraint.DeleteAction); }
internal void WriteAssociationSetElementHeader(DbForeignKeyConstraintMetadata constraint) { _xmlWriter.WriteStartElement(SsdlConstants.Element_AssociationSet); _xmlWriter.WriteAttributeString(SsdlConstants.Attribute_Name, constraint.Name); _xmlWriter.WriteAttributeString( SsdlConstants.Attribute_Association, GetQualifiedTypeName(SsdlConstants.Value_Self, constraint.Name)); }
public static bool ContainsEquivalentForeignKey( this DbTableMetadata table, DbForeignKeyConstraintMetadata foreignKey) { return table.ForeignKeyConstraints .Any( fk => fk.PrincipalTable == foreignKey.PrincipalTable && fk.DependentColumns.SequenceEqual(foreignKey.DependentColumns)); }
private static void GenerateForeignKeyAssociationType( EdmAssociationType associationType, DbDatabaseMapping databaseMapping) { //Contract.Requires(associationType != null); //Contract.Requires(databaseMapping != null); Contract.Assert(associationType.Constraint != null); var dependentEnd = associationType.Constraint.DependentEnd; var principalEnd = associationType.GetOtherEnd(dependentEnd); var principalEntityTypeMapping = GetEntityTypeMappingInHierarchy(databaseMapping, principalEnd.EntityType); var dependentEntityTypeMapping = GetEntityTypeMappingInHierarchy(databaseMapping, dependentEnd.EntityType); var foreignKeyConstraint = new DbForeignKeyConstraintMetadata { Name = associationType.Name, PrincipalTable = principalEntityTypeMapping.TypeMappingFragments.Single().Table, DeleteAction = principalEnd.DeleteAction.HasValue ? (DbOperationAction)principalEnd.DeleteAction.Value : DbOperationAction.None }; foreach (var dependentProperty in associationType.Constraint.DependentProperties) { foreignKeyConstraint.DependentColumns.Add( dependentEntityTypeMapping.GetPropertyMapping(dependentProperty).Column); } foreignKeyConstraint.SetAssociationType(associationType); dependentEntityTypeMapping .TypeMappingFragments .Single() .Table .ForeignKeyConstraints.Add(foreignKeyConstraint); }
protected virtual void VisitDbForeignKeyConstraintMetadata(DbForeignKeyConstraintMetadata item) { VisitDbConstraintMetadata(item); if (item != null) { if (item.HasDependentColumns) { VisitCollection(item.DependentColumns, VisitDbTableColumnMetadata); } VisitDbTableMetadata(item.PrincipalTable); } }
public static void AddTypeConstraint( EdmEntityType entityType, DbTableMetadata principalTable, DbTableMetadata dependentTable, bool isSplitting) { Contract.Requires(principalTable != null); Contract.Requires(dependentTable != null); Contract.Requires(entityType != null); var foreignKeyConstraintMetadata = new DbForeignKeyConstraintMetadata { Name = String.Format( CultureInfo.InvariantCulture, "{0}_TypeConstraint_From_{1}_To_{2}", entityType.Name, principalTable.Name, dependentTable.Name), PrincipalTable = principalTable }; if (isSplitting) { foreignKeyConstraintMetadata.SetIsSplitConstraint(); } else { foreignKeyConstraintMetadata.SetIsTypeConstraint(); } dependentTable.Columns .Where(c => c.IsPrimaryKeyColumn) .Each(c => foreignKeyConstraintMetadata.DependentColumns.Add(c)); dependentTable.ForeignKeyConstraints.Add(foreignKeyConstraintMetadata); //If "DbStoreGeneratedPattern.Identity" was copied from the parent table, it should be removed dependentTable.Columns.Where(c => c.IsPrimaryKeyColumn).Each(c => c.RemoveStoreGeneratedIdentityPattern()); }
private static void SetAllDependentColumns( DbForeignKeyConstraintMetadata fk, IEnumerable<DbTableColumnMetadata> sourceColumns, IEnumerable<DbTableColumnMetadata> destinationColumns) { foreach (var dc in sourceColumns) { fk.DependentColumns.Add( destinationColumns.Single( c => string.Equals(c.Name, dc.Name, StringComparison.Ordinal) || string.Equals(c.GetUnpreferredUniqueName(), dc.Name, StringComparison.Ordinal))); } }
private static void CopyForeignKeyConstraint( DbDatabaseMetadata database, DbTableMetadata toTable, DbForeignKeyConstraintMetadata fk) { Contract.Requires(toTable != null); Contract.Requires(fk != null); var newFk = new DbForeignKeyConstraintMetadata { DeleteAction = fk.DeleteAction, Name = database.Schemas.Single().Tables.SelectMany(t => t.ForeignKeyConstraints). UniquifyName(fk.Name), PrincipalTable = fk.PrincipalTable }; // Make sure all the dependent columns refer to columns in the newTable SetAllDependentColumns(newFk, fk.DependentColumns, toTable.Columns); if (!toTable.ContainsEquivalentForeignKey(newFk)) { toTable.ForeignKeyConstraints.Add(newFk); } }
/// <summary> /// Moves a foreign key constraint from oldTable to newTable and updates column references /// </summary> private static void MoveForeignKeyConstraint( DbTableMetadata fromTable, DbTableMetadata toTable, DbForeignKeyConstraintMetadata fk) { Contract.Requires(fromTable != null); Contract.Requires(toTable != null); Contract.Requires(fk != null); fromTable.ForeignKeyConstraints.Remove(fk); // Only move it to the new table if the destination is not the principal table or if all dependent columns are not FKs // Otherwise you end up with an FK from the PKs to the PKs of the same table if (fk.PrincipalTable != toTable || !fk.DependentColumns.All(c => c.IsPrimaryKeyColumn)) { // Make sure all the dependent columns refer to columns in the newTable var oldColumns = fk.DependentColumns.ToArray(); fk.DependentColumns.Clear(); SetAllDependentColumns(fk, oldColumns, toTable.Columns); if (!toTable.ContainsEquivalentForeignKey(fk)) { toTable.ForeignKeyConstraints.Add(fk); } } }
private static KeyValuePair<string, string> DetermineMultiplicity( DbTableMetadata dependentTable, DbForeignKeyConstraintMetadata constraint) { var principalMultiplicity = CsdlConstants.Value_EndOptional; var dependentMultiplicity = CsdlConstants.Value_EndMany; var isDependentPropertiesFullyCoverKey = false; var isDependentPropertiesHasNullableProperty = false; IEnumerable<DbTableColumnMetadata> dependentProperties = constraint.DependentColumns; if (dependentTable.KeyColumns.Count() == dependentProperties.Count() && dependentTable.KeyColumns.All(k => dependentProperties.Contains(k))) { isDependentPropertiesFullyCoverKey = true; } if (dependentProperties.Any(p => p.IsNullable)) { isDependentPropertiesHasNullableProperty = true; } if (!isDependentPropertiesHasNullableProperty) { principalMultiplicity = CsdlConstants.Value_EndRequired; } if (isDependentPropertiesFullyCoverKey) { principalMultiplicity = CsdlConstants.Value_EndRequired; dependentMultiplicity = CsdlConstants.Value_EndOptional; } return new KeyValuePair<string, string>(principalMultiplicity, dependentMultiplicity); }
private void GenerateIndependentForeignKeyColumns( EdmEntityType principalEntityType, EdmEntityType dependentEntityType, DbAssociationSetMapping associationSetMapping, DbAssociationEndMapping associationEndMapping, DbTableMetadata dependentTable, DbForeignKeyConstraintMetadata foreignKeyConstraint, bool isPrimaryKeyColumn, EdmNavigationProperty principalNavigationProperty) { //Contract.Requires(principalEntityType != null); //Contract.Requires(associationEndMapping != null); //Contract.Requires(dependentTable != null); //Contract.Requires(foreignKeyConstraint != null); foreach (var property in principalEntityType.KeyProperties()) { var foreignKeyColumn = dependentTable.AddColumn( ((principalNavigationProperty != null) ? principalNavigationProperty.Name : principalEntityType.Name) + "_" + property.Name); MapTableColumn(property, foreignKeyColumn, false, isPrimaryKeyColumn); foreignKeyColumn.IsNullable = (associationEndMapping.AssociationEnd.IsOptional() || (associationEndMapping.AssociationEnd.IsRequired() && dependentEntityType.BaseType != null)); foreignKeyColumn.StoreGeneratedPattern = DbStoreGeneratedPattern.None; foreignKeyConstraint.DependentColumns.Add(foreignKeyColumn); associationEndMapping.PropertyMappings.Add( new DbEdmPropertyMapping { Column = foreignKeyColumn, PropertyPath = new[] { property } }); if (foreignKeyColumn.IsNullable) { associationSetMapping.ColumnConditions.Add( new DbColumnCondition { Column = foreignKeyColumn, IsNull = false }); } } }
private void GenerateIndependentForeignKeyConstraint( DbDatabaseMapping databaseMapping, EdmEntityType principalEntityType, EdmEntityType dependentEntityType, DbTableMetadata dependentTable, DbAssociationSetMapping associationSetMapping, DbAssociationEndMapping associationEndMapping, string name, EdmAssociationEnd principalEnd, bool isPrimaryKeyColumn = false) { //Contract.Requires(databaseMapping != null); //Contract.Requires(principalEntityType != null); //Contract.Requires(dependentTable != null); //Contract.Requires(associationEndMapping != null); //Contract.Requires(!string.IsNullOrWhiteSpace(name)); var principalTable = GetEntityTypeMappingInHierarchy(databaseMapping, principalEntityType) .TypeMappingFragments .Single() .Table; var foreignKeyConstraint = new DbForeignKeyConstraintMetadata { Name = name, PrincipalTable = principalTable, DeleteAction = associationEndMapping.AssociationEnd.DeleteAction.HasValue ? (DbOperationAction) associationEndMapping.AssociationEnd.DeleteAction. Value : DbOperationAction.None }; var principalNavigationProperty = databaseMapping.Model.GetEntityTypes() .SelectMany(e => e.DeclaredNavigationProperties) .SingleOrDefault(n => n.ResultEnd == principalEnd); GenerateIndependentForeignKeyColumns( principalEntityType, dependentEntityType, associationSetMapping, associationEndMapping, dependentTable, foreignKeyConstraint, isPrimaryKeyColumn, principalNavigationProperty); dependentTable.ForeignKeyConstraints.Add(foreignKeyConstraint); }