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;
        }
Exemple #2
0
        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;
        }