private void ConfigureDependentBehavior( EdmAssociationType associationType, EdmModel model, EntityTypeConfiguration entityTypeConfiguration) { //Contract.Requires(associationType != null); //Contract.Requires(model != null); //Contract.Requires(entityTypeConfiguration != null); EdmAssociationEnd principalEnd; EdmAssociationEnd dependentEnd; if (!associationType.TryGuessPrincipalAndDependentEnds(out principalEnd, out dependentEnd)) { if (IsNavigationPropertyDeclaringTypePrincipal.HasValue) { associationType.MarkPrincipalConfigured(); var navProp = model.Namespaces .SelectMany(ns => ns.EntityTypes) .SelectMany(et => et.DeclaredNavigationProperties) .Where(np => np.GetClrPropertyInfo().IsSameAs(NavigationProperty)) .Single(); principalEnd = IsNavigationPropertyDeclaringTypePrincipal.Value ? associationType.GetOtherEnd(navProp.ResultEnd) : navProp.ResultEnd; dependentEnd = associationType.GetOtherEnd(principalEnd); if (associationType.SourceEnd != principalEnd) { // need to move around source to be principal, target to be dependent so Edm services will use the correct // principal and dependent ends. The Edm default Db + mapping service tries to guess principal/dependent // based on multiplicities, but if it can't figure it out, it will use source as principal and target as dependent associationType.SourceEnd = principalEnd; associationType.TargetEnd = dependentEnd; var associationSet = model.Containers .SelectMany(ct => ct.AssociationSets) .Where(aset => aset.ElementType == associationType).Single(); var sourceSet = associationSet.SourceSet; associationSet.SourceSet = associationSet.TargetSet; associationSet.TargetSet = sourceSet; } } if (principalEnd == null) { dependentEnd = associationType.TargetEnd; } } ConfigureConstraint(associationType, dependentEnd, entityTypeConfiguration); ConfigureDeleteAction(associationType.GetOtherEnd(dependentEnd)); }
public void TryGuessPrincipalAndDependentEnds_should_return_correct_ends_for_optional_to_required() { var associationType = new EdmAssociationType().Initialize(); associationType.SourceEnd.EndKind = EdmAssociationEndKind.Optional; associationType.TargetEnd.EndKind = EdmAssociationEndKind.Required; EdmAssociationEnd principalEnd, dependentEnd; associationType.TryGuessPrincipalAndDependentEnds(out principalEnd, out dependentEnd); Assert.Same(associationType.TargetEnd, principalEnd); Assert.Same(associationType.SourceEnd, dependentEnd); }
private static void UpdatePrincipalTables( DbDatabaseMapping databaseMapping, DbTableMetadata toTable, bool removeFks, EdmAssociationType associationType, EdmEntityType et) { EdmAssociationEnd principalEnd, dependentEnd; var endsToCheck = new List<EdmAssociationEnd>(); if (associationType.TryGuessPrincipalAndDependentEnds(out principalEnd, out dependentEnd)) { endsToCheck.Add(principalEnd); } else if (associationType.SourceEnd.EndKind == EdmAssociationEndKind.Many && associationType.TargetEnd.EndKind == EdmAssociationEndKind.Many) { // many to many consider both ends endsToCheck.Add(associationType.SourceEnd); endsToCheck.Add(associationType.TargetEnd); } else { // 1:1 and 0..1:0..1 endsToCheck.Add(associationType.SourceEnd); } foreach (var end in endsToCheck) { if (end.EntityType == et) { IEnumerable<KeyValuePair<DbTableMetadata, IEnumerable<DbTableColumnMetadata>>> dependentTableInfos; if (associationType.Constraint != null) { var originalDependentType = associationType.GetOtherEnd(end).EntityType; var allDependentTypes = databaseMapping.Model.GetSelfAndAllDerivedTypes(originalDependentType); dependentTableInfos = allDependentTypes.Select(t => databaseMapping.GetEntityTypeMapping(t)).Where( dm => dm != null) .SelectMany( dm => dm.TypeMappingFragments .Where( tmf => associationType.Constraint.DependentProperties .All( p => tmf.PropertyMappings.Any( pm => pm.PropertyPath.First() == p)))) .Distinct((f1, f2) => f1.Table == f2.Table) .Select( df => new KeyValuePair<DbTableMetadata, IEnumerable<DbTableColumnMetadata>>( df.Table, df.PropertyMappings.Where( pm => associationType.Constraint.DependentProperties.Contains( pm.PropertyPath.First())).Select( pm => pm.Column))); } else { // IA var associationSetMapping = databaseMapping.EntityContainerMappings.Single().AssociationSetMappings.Where( asm => asm.AssociationSet.ElementType == associationType).Single(); var dependentTable = associationSetMapping.Table; var propertyMappings = associationSetMapping.SourceEndMapping.AssociationEnd == end ? associationSetMapping.SourceEndMapping.PropertyMappings : associationSetMapping.TargetEndMapping.PropertyMappings; var dependentColumns = propertyMappings.Select(pm => pm.Column); dependentTableInfos = new[] { new KeyValuePair <DbTableMetadata, IEnumerable<DbTableColumnMetadata>>( dependentTable, dependentColumns) }; } foreach (var tableInfo in dependentTableInfos) { foreach ( var fk in tableInfo.Key.ForeignKeyConstraints.Where( fk => fk.DependentColumns.SequenceEqual(tableInfo.Value)).ToArray( )) { if (removeFks) { tableInfo.Key.ForeignKeyConstraints.Remove(fk); } else { fk.PrincipalTable = toTable; } } } } } }
private void GenerateIndependentAssociationType( EdmAssociationType associationType, DbDatabaseMapping databaseMapping) { //Contract.Requires(associationType != null); //Contract.Requires(databaseMapping != null); EdmAssociationEnd principalEnd, dependentEnd; if (!associationType.TryGuessPrincipalAndDependentEnds(out principalEnd, out dependentEnd)) { if (!associationType.IsPrincipalConfigured()) { throw Error.UnableToDeterminePrincipal( associationType.SourceEnd.EntityType.GetClrType(), associationType.TargetEnd.EntityType.GetClrType()); } principalEnd = associationType.SourceEnd; dependentEnd = associationType.TargetEnd; } var dependentEntityTypeMapping = GetEntityTypeMappingInHierarchy(databaseMapping, dependentEnd.EntityType); var dependentTable = dependentEntityTypeMapping .TypeMappingFragments .First() .Table; var associationSetMapping = GenerateAssociationSetMapping( associationType, databaseMapping, principalEnd, dependentEnd, dependentTable); GenerateIndependentForeignKeyConstraint( databaseMapping, principalEnd.EntityType, dependentEnd.EntityType, dependentTable, associationSetMapping, associationSetMapping.SourceEndMapping, associationType.Name, principalEnd); foreach (var property in dependentEnd.EntityType.KeyProperties()) { associationSetMapping.TargetEndMapping.PropertyMappings.Add( new DbEdmPropertyMapping { Column = dependentEntityTypeMapping.GetPropertyMapping(property).Column, PropertyPath = new[] { property } }); } }