internal static IEnumerable<Command> LaunchReferentialConstraintDialog(Association association) { var commands = new List<Command>(); if (association != null) { if (association.ReferentialConstraint == null || (association.ReferentialConstraint != null && association.ReferentialConstraint.Principal != null && association.ReferentialConstraint.Principal.Role.Target != null && association.ReferentialConstraint.Principal.Role.Target.Type.Target != null && association.ReferentialConstraint.Dependent != null && association.ReferentialConstraint.Dependent.Role.Target != null && association.ReferentialConstraint.Dependent.Role.Target.Type.Target != null ) ) { using (var dlg = new ReferentialConstraintDialog(association)) { var result = dlg.ShowDialog(); if (result != DialogResult.Cancel && dlg.Principal != null && dlg.Dependent != null) { if (association.ReferentialConstraint != null) { // first, enqueue the delete command (always) commands.Add(association.ReferentialConstraint.GetDeleteCommand()); } if (dlg.ShouldDeleteOnly == false) { var principalProps = new List<Property>(); var dependentProps = new List<Property>(); var keys = GetKeysForType(dlg.Principal.Type.Target); foreach (var mli in dlg.MappingList) { if (mli.IsValidPrincipalKey) { // try to resolve the symbol into a property Property p = null; Property d = null; if (mli.PrincipalKey != null) { p = GetKeyForType(mli.PrincipalKey, dlg.Principal.Type.Target, keys); } if (mli.DependentProperty != null) { d = dlg.Dependent.Artifact.ArtifactSet.LookupSymbol(mli.DependentProperty) as Property; } if (p != null && d != null) { principalProps.Add(p); dependentProps.Add(d); } } } // now enqueue the command to create a new one if the user didn't click Delete Debug.Assert( principalProps.Count == dependentProps.Count, "principal (" + principalProps.Count + ") & dependent (" + dependentProps.Count + ") property counts must match!"); if (principalProps.Count > 0) { Command cmd = new CreateReferentialConstraintCommand( dlg.Principal, dlg.Dependent, principalProps, dependentProps); commands.Add(cmd); } } } } } else { VsUtils.ShowMessageBox( PackageManager.Package, Resources.Error_CannotEditRefConstraint, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING); } } return commands; }
private void CopyAssociation( CommandProcessorContext cpc, BaseEntityModel model, AssociationClipboardFormat clipboardAssociation , Dictionary <EntityTypeClipboardFormat, EntityType> entitiesMap) { var associationName = ModelHelper.GetUniqueName(typeof(Association), model, clipboardAssociation.AssociationName); var clipboardEntity1 = clipboardAssociation.ClipboardEntity1; var clipboardEntity2 = clipboardAssociation.ClipboardEntity2; var entity1 = entitiesMap[clipboardEntity1] as ConceptualEntityType; var entity2 = entitiesMap[clipboardEntity2] as ConceptualEntityType; Debug.Assert(entity1 != null, "entity1 is not a ConceptualEntityType"); Debug.Assert(entity2 != null, "entity2 is not a ConceptualEntityType"); var navigationPropertyEntity1 = clipboardEntity1.GetNavigationPropertyClipboard( clipboardAssociation.AssociationName, clipboardAssociation.AssociationEndRole1); var navigationPropertyEntity2 = clipboardEntity2.GetNavigationPropertyClipboard( clipboardAssociation.AssociationName, clipboardAssociation.AssociationEndRole2); var navigationPropertyName1 = navigationPropertyEntity1 != null ? ModelHelper.GetUniqueConceptualPropertyName(navigationPropertyEntity1.PropertyName, entity1) : null; string navigationPropertyName2 = null; if (entity1 == entity2) { // if this is a self-association then the NavProp for end2 needs a different name from end1 navigationPropertyName2 = ModelHelper.GetUniqueConceptualPropertyName( (navigationPropertyEntity2 != null ? navigationPropertyEntity2.PropertyName : entity1.LocalName.Value), entity2, new HashSet <string> { navigationPropertyName1 }); } else { navigationPropertyName2 = ModelHelper.GetUniqueConceptualPropertyName( (navigationPropertyEntity2 != null ? navigationPropertyEntity2.PropertyName : entity1.LocalName.Value), entity2); } var cmd = new CreateConceptualAssociationCommand( associationName, entity1, clipboardAssociation.Multiplicity1, navigationPropertyName1, entity2, clipboardAssociation.Multiplicity2, navigationPropertyName2, true, false); CommandProcessor.InvokeSingleCommand(cpc, cmd); // copy nav prop facets & structured annotations if (navigationPropertyEntity1 != null) { var np1 = entity1.FindNavigationPropertyForEnd(cmd.End1); CommandProcessor.InvokeSingleCommand( cpc, new SetNavigationPropertyFacetsCommand( np1, navigationPropertyEntity1.GetterAccessModifier, navigationPropertyEntity1.SetterAccessModifier)); AddAnnotations(navigationPropertyEntity1, np1); } if (navigationPropertyEntity2 != null) { var np2 = entity2.FindNavigationPropertyForEnd(cmd.End2); CommandProcessor.InvokeSingleCommand( cpc, new SetNavigationPropertyFacetsCommand( np2, navigationPropertyEntity2.GetterAccessModifier, navigationPropertyEntity2.SetterAccessModifier)); AddAnnotations(navigationPropertyEntity2, np2); } if (clipboardAssociation.ReferentialConstraint != null) { EntityType principal; EntityType dependent; if (entity1 == FindEntityByClipboardName(clipboardAssociation.ReferentialConstraint.PrincipalEntityName, entitiesMap)) { principal = entity1; dependent = entity2; } else { Debug.Assert( entity2 == FindEntityByClipboardName(clipboardAssociation.ReferentialConstraint.PrincipalEntityName, entitiesMap), "could not find entity using clipboard name " + clipboardAssociation.ReferentialConstraint.PrincipalEntityName); principal = entity2; dependent = entity1; } IEnumerable <Property> principalPropertyList = null; IEnumerable <Property> dependentPropertyList = null; var associationEnds = cmd.CreatedAssociation.AssociationEnds(); if (associationEnds.Count == 2 && (principalPropertyList = ModelHelper.FindProperties(principal, clipboardAssociation.ReferentialConstraint.PrincipalProperties)) != null && (dependentPropertyList = ModelHelper.FindProperties(dependent, clipboardAssociation.ReferentialConstraint.DependentProperties)) != null) { var refCmd = new CreateReferentialConstraintCommand( associationEnds[0], associationEnds[1], principalPropertyList, dependentPropertyList ); CommandProcessor.InvokeSingleCommand(cpc, refCmd); AddAnnotations(clipboardAssociation.ReferentialConstraint, refCmd.ReferentialConstraint); } } // add structured annotations to the association AddAnnotations(clipboardAssociation, cmd.CreatedAssociation); }
private void CopyAssociation( CommandProcessorContext cpc, BaseEntityModel model, AssociationClipboardFormat clipboardAssociation , Dictionary<EntityTypeClipboardFormat, EntityType> entitiesMap) { var associationName = ModelHelper.GetUniqueName(typeof(Association), model, clipboardAssociation.AssociationName); var clipboardEntity1 = clipboardAssociation.ClipboardEntity1; var clipboardEntity2 = clipboardAssociation.ClipboardEntity2; var entity1 = entitiesMap[clipboardEntity1] as ConceptualEntityType; var entity2 = entitiesMap[clipboardEntity2] as ConceptualEntityType; Debug.Assert(entity1 != null, "entity1 is not a ConceptualEntityType"); Debug.Assert(entity2 != null, "entity2 is not a ConceptualEntityType"); var navigationPropertyEntity1 = clipboardEntity1.GetNavigationPropertyClipboard( clipboardAssociation.AssociationName, clipboardAssociation.AssociationEndRole1); var navigationPropertyEntity2 = clipboardEntity2.GetNavigationPropertyClipboard( clipboardAssociation.AssociationName, clipboardAssociation.AssociationEndRole2); var navigationPropertyName1 = navigationPropertyEntity1 != null ? ModelHelper.GetUniqueConceptualPropertyName(navigationPropertyEntity1.PropertyName, entity1) : null; string navigationPropertyName2 = null; if (entity1 == entity2) { // if this is a self-association then the NavProp for end2 needs a different name from end1 navigationPropertyName2 = ModelHelper.GetUniqueConceptualPropertyName( (navigationPropertyEntity2 != null ? navigationPropertyEntity2.PropertyName : entity1.LocalName.Value), entity2, new HashSet<string> { navigationPropertyName1 }); } else { navigationPropertyName2 = ModelHelper.GetUniqueConceptualPropertyName( (navigationPropertyEntity2 != null ? navigationPropertyEntity2.PropertyName : entity1.LocalName.Value), entity2); } var cmd = new CreateConceptualAssociationCommand( associationName, entity1, clipboardAssociation.Multiplicity1, navigationPropertyName1, entity2, clipboardAssociation.Multiplicity2, navigationPropertyName2, true, false); CommandProcessor.InvokeSingleCommand(cpc, cmd); // copy nav prop facets & structured annotations if (navigationPropertyEntity1 != null) { var np1 = entity1.FindNavigationPropertyForEnd(cmd.End1); CommandProcessor.InvokeSingleCommand( cpc, new SetNavigationPropertyFacetsCommand( np1, navigationPropertyEntity1.GetterAccessModifier, navigationPropertyEntity1.SetterAccessModifier)); AddAnnotations(navigationPropertyEntity1, np1); } if (navigationPropertyEntity2 != null) { var np2 = entity2.FindNavigationPropertyForEnd(cmd.End2); CommandProcessor.InvokeSingleCommand( cpc, new SetNavigationPropertyFacetsCommand( np2, navigationPropertyEntity2.GetterAccessModifier, navigationPropertyEntity2.SetterAccessModifier)); AddAnnotations(navigationPropertyEntity2, np2); } if (clipboardAssociation.ReferentialConstraint != null) { EntityType principal; EntityType dependent; if (entity1 == FindEntityByClipboardName(clipboardAssociation.ReferentialConstraint.PrincipalEntityName, entitiesMap)) { principal = entity1; dependent = entity2; } else { Debug.Assert( entity2 == FindEntityByClipboardName(clipboardAssociation.ReferentialConstraint.PrincipalEntityName, entitiesMap), "could not find entity using clipboard name " + clipboardAssociation.ReferentialConstraint.PrincipalEntityName); principal = entity2; dependent = entity1; } IEnumerable<Property> principalPropertyList = null; IEnumerable<Property> dependentPropertyList = null; var associationEnds = cmd.CreatedAssociation.AssociationEnds(); if (associationEnds.Count == 2 && (principalPropertyList = ModelHelper.FindProperties(principal, clipboardAssociation.ReferentialConstraint.PrincipalProperties)) != null && (dependentPropertyList = ModelHelper.FindProperties(dependent, clipboardAssociation.ReferentialConstraint.DependentProperties)) != null) { var refCmd = new CreateReferentialConstraintCommand( associationEnds[0], associationEnds[1], principalPropertyList, dependentPropertyList ); CommandProcessor.InvokeSingleCommand(cpc, refCmd); AddAnnotations(clipboardAssociation.ReferentialConstraint, refCmd.ReferentialConstraint); } } // add structured annotations to the association AddAnnotations(clipboardAssociation, cmd.CreatedAssociation); }
public void Invoke() { Debug.Assert(_association != null, "The Association reference is null"); // if the association was deleted in this transaction, just return since we won't need to process it if (_association == null || _association.XObject == null) { return; } // if foreign keys are supported in this EF version, then we skip all processing here. if (EdmFeatureManager.GetForeignKeysInModelFeatureState(_association.Artifact.SchemaVersion).IsEnabled()) { return; } Debug.Assert(_association.EntityModel.IsCSDL, "Inferring ref constraints isn't valid for SSDL associations"); Debug.Assert( _association.AssociationEnds().Count == 2, "The association to be processed does not have 2 ends while trying to infer ref constraints"); Debug.Assert( _association.AssociationSet != null, "The association being processed does not have a valid AssociationSet while trying to infer ref constraints"); // some local aliases for readability var end1 = _association.AssociationEnds()[0]; var end2 = _association.AssociationEnds()[1]; Debug.Assert(end1 != null && end2 != null, "Null end found while trying to infer ref constraints"); if (end1 == null || end2 == null) { return; } // regardless, we will remove the constraint if (_association.ReferentialConstraint != null) { DeleteEFElementCommand.DeleteInTransaction(_context, _association.ReferentialConstraint); } // we will never create a constraint against a self-association if (end1.Type.Target == end2.Type.Target) { return; } AssociationEnd principal = null; AssociationEnd dependent = null; ModelHelper.DeterminePrincipalDependentAssociationEnds( _association, out principal, out dependent, ModelHelper.DeterminePrincipalDependentAssociationEndsScenario.InferReferentialConstraint); // We found our principal and dependent ends but we still need to confirm that // the AssociationSetMapping contains key properties that are mapped to the same column if (principal != null && principal.Type.Target != null && dependent != null && dependent.Type.Target != null) { var associationSet = _association.AssociationSet; if (associationSet != null) { var asm = associationSet.AssociationSetMapping; if (asm != null && asm.EndProperties().Count == 2) { // any commonly mapped properties will be loaded into these HashSets var principalPropertyRefs = new HashSet<Property>(); var dependentPropertyRefs = new HashSet<Property>(); EndProperty dependentEndProperty = null; EndProperty principalEndProperty = null; var endProp1 = asm.EndProperties()[0]; var endProp2 = asm.EndProperties()[1]; if (endProp1.Name.Target != null) { if (endProp1.Name.Target.Role.Target == dependent) { dependentEndProperty = endProp1; principalEndProperty = endProp2; } else { dependentEndProperty = endProp2; principalEndProperty = endProp1; } } Debug.Assert( dependentEndProperty != null && principalEndProperty != null, "Either dependent or principal EndProperty is null"); if (dependentEndProperty != null && principalEndProperty != null) { // for each column that is mapped to a key property on the dependent end, determine if there is a // key property on the principal end that it is also mapped to. If there is, then we need a // ReferentialConstraint foreach (var dependentScalarProp in dependentEndProperty.ScalarProperties()) { var principalScalarProp = principalEndProperty.ScalarProperties() .FirstOrDefault(psp => psp.ColumnName.Target == dependentScalarProp.ColumnName.Target); if (principalScalarProp != null) { principalPropertyRefs.Add(principalScalarProp.Name.Target); dependentPropertyRefs.Add(dependentScalarProp.Name.Target); } } Debug.Assert( principalPropertyRefs.Count == dependentPropertyRefs.Count, "List of keys are mismatched while trying to create a Ref Constraint"); if (principalPropertyRefs.Count > 0 && dependentPropertyRefs.Count > 0 && principalPropertyRefs.Count == dependentPropertyRefs.Count) { // if the propertyRefs sets have any data in them, add the constraint var cmd = new CreateReferentialConstraintCommand( principal, dependent, principalPropertyRefs, dependentPropertyRefs); CommandProcessor.InvokeSingleCommand(_context, cmd); } } } } } }
public void Invoke() { Debug.Assert(_association != null, "The Association reference is null"); // if the association was deleted in this transaction, just return since we won't need to process it if (_association == null || _association.XObject == null) { return; } // if foreign keys aren't supported in this EF version, then we skip all processing here. if (!EdmFeatureManager.GetForeignKeysInModelFeatureState(_association.Artifact.SchemaVersion).IsEnabled()) { return; } Debug.Assert(_association.EntityModel.IsCSDL, "Creating foreign key properties isn't valid for SSDL associations"); Debug.Assert( _association.AssociationEnds().Count == 2, "The association to be processed does not have 2 ends while trying to create foreign key properties"); Debug.Assert( _association.AssociationSet != null, "The association being processed does not have a valid AssociationSet while trying to create foreign key properties"); // remove any existing RC if (_association.ReferentialConstraint != null) { DeleteEFElementCommand.DeleteInTransaction(_context, _association.ReferentialConstraint); } // figure out the principal and dependent ends AssociationEnd principal = null; AssociationEnd dependent = null; ModelHelper.DeterminePrincipalDependentAssociationEnds( _association, out principal, out dependent, ModelHelper.DeterminePrincipalDependentAssociationEndsScenario.CreateForeignKeyProperties); if (principal != null && principal.Type.Target != null && dependent != null && dependent.Type.Target != null) { // many-to-many associations don't need foreign key properties if (principal.Multiplicity.Value == ModelConstants.Multiplicity_Many && dependent.Multiplicity.Value == ModelConstants.Multiplicity_Many) { return; } var principalPropertyRefs = new HashSet<Property>(); var dependentPropertyRefs = new HashSet<Property>(); // add properties to the dependent side IEnumerable<Property> pkeys; var cet = principal.Type.Target as ConceptualEntityType; if (cet != null) { // the principal is a c-side entity pkeys = cet.ResolvableTopMostBaseType.ResolvableKeys; } else { // the principal is an s-side entity pkeys = principal.Type.Target.ResolvableKeys; } foreach (var pkey in pkeys) { // build up the foreign key name, add an '_' if the resulting name wouldn't be camel-case // e.g. // Order and Id become "OrderId" // order and id become "order_id" // // get a unique name for this new property var fkeyName = string.Format( CultureInfo.CurrentCulture, "{0}{1}{2}", principal.Type.Target.LocalName.Value, (char.IsUpper(pkey.LocalName.Value, 0) ? "" : "_"), pkey.LocalName.Value); fkeyName = ModelHelper.GetUniqueName(typeof(Property), dependent.Type.Target, fkeyName); // tweak the properties; we are using the copy/paste process since we have to // copy all facets of the pk and that code does this already var pcf = new PropertyClipboardFormat(pkey); pcf.PropertyName = fkeyName; pcf.IsKeyProperty = false; pcf.IsNullable = (principal.Multiplicity.Value == ModelConstants.Multiplicity_ZeroOrOne ? true : false); pcf.StoreGeneratedPattern = string.Empty; pcf.GetterAccessModifier = string.Empty; pcf.SetterAccessModifier = string.Empty; // create the new property var cmd = new CopyPropertyCommand(pcf, dependent.Type.Target); CommandProcessor.InvokeSingleCommand(_context, cmd); var fkey = cmd.Property; // build up our list of keys Debug.Assert(fkey != null, "CreateForeignKeyProperties was not able to create a foreign key"); if (fkey != null) { principalPropertyRefs.Add(pkey); dependentPropertyRefs.Add(fkey); } } // create the new RC Debug.Assert( principalPropertyRefs.Count == dependentPropertyRefs.Count, "List of keys are mismatched while trying to create a Ref Constraint"); if (principalPropertyRefs.Count > 0 && dependentPropertyRefs.Count > 0 && principalPropertyRefs.Count == dependentPropertyRefs.Count) { var cmd = new CreateReferentialConstraintCommand(principal, dependent, principalPropertyRefs, dependentPropertyRefs); CommandProcessor.InvokeSingleCommand(_context, cmd); } } }
AddReferentialConstraintForAssociation( CommandProcessorContext cpc, CreateConceptualAssociationCommand cmd, bool end1IsPrincipalEnd, List<Property> principalPropertiesInExistingArtifact, List<Property> dependentPropertiesInExistingArtifact) { if (cmd.End1 == null) { Debug.Fail("Should not have null AssociationEnd End1 from CreateConceptualAssociationCommand"); return null; } else if (cmd.End2 == null) { Debug.Fail("Should not have null AssociationEnd End2 from CreateConceptualAssociationCommand"); return null; } //assign principal and dependent ends var principalEndInExistingArtifact = end1IsPrincipalEnd ? cmd.End1 : cmd.End2; var dependentEndInExistingArtifact = end1IsPrincipalEnd ? cmd.End2 : cmd.End1; // now create the referential constraint var rcCmd = new CreateReferentialConstraintCommand( principalEndInExistingArtifact, dependentEndInExistingArtifact, principalPropertiesInExistingArtifact, dependentPropertiesInExistingArtifact); CommandProcessor.InvokeSingleCommand(cpc, rcCmd); var newRC = rcCmd.ReferentialConstraint; return newRC; }