protected override void InvokeInternal(CommandProcessorContext cpc) { var service = cpc.EditingContext.GetEFArtifactService(); var artifact = service.Artifact; // the model that we want to add the association to var model = artifact.StorageModel(); // check for uniqueness var assocName = Name; var assocSetName = assocName; if (UniquifyNames) { assocName = ModelHelper.GetUniqueName(typeof(Association), model, assocName); assocSetName = ModelHelper.GetUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocName); } else { // check for uniqueness of the association name string msg = null; if (ModelHelper.IsUniqueName(typeof(Association), model, assocName, false, out msg) == false) { throw new InvalidOperationException(msg); } // check for uniqueness of the association set name if (ModelHelper.IsUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocSetName, false, out msg) == false) { throw new InvalidOperationException(msg); } } // create the new item in our model var association = new Association(model, null); association.LocalName.Value = assocName; model.AddAssociation(association); XmlModelHelper.NormalizeAndResolve(association); // create the ends of the association var fkEnd = new AssociationEnd(association, null); fkEnd.Type.SetRefName(FkTable); fkEnd.Role.Value = FkRoleNameOverride ?? ModelHelper.CreateFKAssociationEndName(FkTable.LocalName.Value); if (FkMultiplicityOverride != null) { fkEnd.Multiplicity.Value = FkMultiplicityOverride; } else { fkEnd.Multiplicity.Value = DoesFkFormPk ? ModelConstants.Multiplicity_ZeroOrOne : ModelConstants.Multiplicity_Many; } association.AddAssociationEnd(fkEnd); XmlModelHelper.NormalizeAndResolve(fkEnd); var pkEnd = new AssociationEnd(association, null); pkEnd.Type.SetRefName(PkTable); pkEnd.Role.Value = PkRoleNameOverride ?? ModelHelper.CreatePKAssociationEndName(PkTable.LocalName.Value); if (PkMultiplicityOverride != null) { pkEnd.Multiplicity.Value = PkMultiplicityOverride; } else { pkEnd.Multiplicity.Value = IsNullableFk ? ModelConstants.Multiplicity_ZeroOrOne : ModelConstants.Multiplicity_One; } association.AddAssociationEnd(pkEnd); XmlModelHelper.NormalizeAndResolve(pkEnd); var cmd = new CreateAssociationSetCommand(assocSetName, association, ModelSpace.Storage); CommandProcessor.InvokeSingleCommand(cpc, cmd); var set = cmd.AssociationSet; Debug.Assert(set != null, "failed to create an AssociationSet"); Association = association; _createdAssociationFkEnd = fkEnd; _createdAssociationPkEnd = pkEnd; }
protected override void InvokeInternal(CommandProcessorContext cpc) { var service = cpc.EditingContext.GetEFArtifactService(); var artifact = service.Artifact; // the model that we want to add the association to var model = artifact.ConceptualModel(); // check for uniqueness of the assocation and association set names // if uniquifyNames is true then make them unique, otherwise throw // an exception if they're not (always uniquify associationSetName // regardless as we get bugs if not) var assocName = Name; var assocSetName = assocName; if (UniquifyNames) { assocName = ModelHelper.GetUniqueName(typeof(Association), model, assocName); assocSetName = ModelHelper.GetUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocName); // ensure unique NavigationProperty names if (ShouldCreateNavigationPropertyEnd1 && !ModelHelper.IsUniquePropertyName(End1Entity, NavigationPropertyInEnd1Entity, true) || NavigationPropertyInEnd1Entity == End1Entity.LocalName.Value) { var namesToAvoid = new HashSet <string>(); namesToAvoid.Add(End1Entity.LocalName.Value); namesToAvoid.Add(NavigationPropertyInEnd2Entity); NavigationPropertyInEnd1Entity = ModelHelper.GetUniqueConceptualPropertyName( NavigationPropertyInEnd1Entity, End1Entity, namesToAvoid); } if (ShouldCreateNavigationPropertyEnd2 && !ModelHelper.IsUniquePropertyName(End2Entity, NavigationPropertyInEnd2Entity, true) || NavigationPropertyInEnd2Entity == End2Entity.LocalName.Value) { var namesToAvoid = new HashSet <string> { End2Entity.LocalName.Value, NavigationPropertyInEnd1Entity }; NavigationPropertyInEnd2Entity = ModelHelper.GetUniqueConceptualPropertyName( NavigationPropertyInEnd2Entity, End2Entity, namesToAvoid); } } else { assocSetName = ModelHelper.GetUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocName); string msg = null; if (!ModelHelper.IsUniqueName(typeof(Association), model, assocName, false, out msg)) { throw new InvalidOperationException(msg); } else if (!ModelHelper.IsUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocSetName, false, out msg)) { throw new InvalidOperationException(msg); } else if (ShouldCreateNavigationPropertyEnd1 && (!ModelHelper.IsUniquePropertyName(End1Entity, NavigationPropertyInEnd1Entity, true))) { msg = string.Format(CultureInfo.CurrentCulture, Resources.NAME_NOT_UNIQUE, NavigationPropertyInEnd1Entity); throw new InvalidOperationException(msg); } else if (ShouldCreateNavigationPropertyEnd2 && (!ModelHelper.IsUniquePropertyName(End2Entity, NavigationPropertyInEnd2Entity, true))) { msg = string.Format(CultureInfo.CurrentCulture, Resources.NAME_NOT_UNIQUE, NavigationPropertyInEnd2Entity); throw new InvalidOperationException(msg); } else if (NavigationPropertyInEnd1Entity == End1Entity.LocalName.Value) { msg = string.Format( CultureInfo.CurrentCulture, Resources.NavPropNameSameAsContainer, NavigationPropertyInEnd1Entity); throw new InvalidOperationException(msg); } else if (NavigationPropertyInEnd2Entity == End2Entity.LocalName.Value) { msg = string.Format( CultureInfo.CurrentCulture, Resources.NavPropNameSameAsContainer, NavigationPropertyInEnd2Entity); throw new InvalidOperationException(msg); } } // create the new item in our model var association = new Association(model, null); association.LocalName.Value = assocName; model.AddAssociation(association); XmlModelHelper.NormalizeAndResolve(association); // create the first end _end1 = new AssociationEnd(association, null); _end1.Type.SetRefName(End1Entity); _end1.Role.Value = End1Entity.LocalName.Value; _end1.Multiplicity.Value = End1Multiplicity; association.AddAssociationEnd(_end1); XmlModelHelper.NormalizeAndResolve(_end1); // create the second end _end2 = new AssociationEnd(association, null); _end2.Type.SetRefName(End2Entity); var endRoleValue = End2Entity.LocalName.Value; if (_end1.Role.Value.Equals(endRoleValue)) { // avoid duplicate Role values between the two ends. This will occur in self-associations. // Appending "1" is consistent with how model-gen chooses a unique name. endRoleValue = endRoleValue + "1"; } _end2.Role.Value = endRoleValue; _end2.Multiplicity.Value = End2Multiplicity; association.AddAssociationEnd(_end2); XmlModelHelper.NormalizeAndResolve(_end2); // create the association set for this association var cmd = new CreateAssociationSetCommand(assocSetName, association); CommandProcessor.InvokeSingleCommand(cpc, cmd); var set = cmd.AssociationSet; Debug.Assert(set != null, "unable to create association set"); CreateNavigationPropertyCommand navcmd; if (ShouldCreateNavigationPropertyEnd1) { navcmd = new CreateNavigationPropertyCommand(NavigationPropertyInEnd1Entity, End1Entity, association, _end1, _end2); CommandProcessor.InvokeSingleCommand(cpc, navcmd); } if (ShouldCreateNavigationPropertyEnd2) { navcmd = new CreateNavigationPropertyCommand(NavigationPropertyInEnd2Entity, End2Entity, association, _end2, _end1); CommandProcessor.InvokeSingleCommand(cpc, navcmd); } if (ShouldCreateForeignKeyProperties) { CreateForeignKeyProperties.AddRule(cpc, association); } CreatedAssociation = association; }
protected override void InvokeInternal(CommandProcessorContext cpc) { CreatedAssociation = ModelHelper.FindAssociation(cpc.Artifact.ConceptualModel(), Name); if (CreatedAssociation == null) { // This Association does not exist, create it base.InvokeInternal(cpc); } else { // The Association already exists, update it Debug.Assert( CreatedAssociation.AssociationEnds().Count == 2, "Association element is invalid, it should always have exactly 2 ends"); if (CreatedAssociation.AssociationEnds().Count == 2) { AssociationEnd principal; AssociationEnd dependent; ModelHelper.DeterminePrincipalDependentEndsForAnyAssociationType(CreatedAssociation, out principal, out dependent); if (principal.Type.Target == null || !string.Equals(principal.Type.Target.Name.Value, End1Entity.LocalName.Value, StringComparison.Ordinal)) { principal.Type.SetRefName(End1Entity); principal.Role.Value = End1Entity.LocalName.Value; } if (dependent.Type.Target == null || !string.Equals(dependent.Type.Target.Name.Value, End2Entity.LocalName.Value, StringComparison.Ordinal)) { dependent.Type.SetRefName(End2Entity); var endRoleValue = End2Entity.LocalName.Value; if (principal.Role.Value.Equals(endRoleValue)) { // avoid duplicate Role values between the two ends. This will occur in self-associations. // Appending "1" is consistent with how model-gen chooses a unique name. endRoleValue = endRoleValue + "1"; } dependent.Role.Value = endRoleValue; } if (!string.Equals(principal.Multiplicity.Value, End1Multiplicity, StringComparison.Ordinal)) { principal.Multiplicity.Value = End1Multiplicity; } if (!string.Equals(dependent.Multiplicity.Value, End2Multiplicity, StringComparison.Ordinal)) { dependent.Multiplicity.Value = End2Multiplicity; } // We have to resolve the association after both the principal and dependent have been updated here. The reason is because // if we resolve the principal and dependent separately we will end up with duplicate symbols in the symbol table because // the previous end didn't get removed. XmlModelHelper.NormalizeAndResolve(CreatedAssociation); // Also update the AssociationSet var associationSet = CreatedAssociation.AssociationSet; // It's possible for the association to exist but not the associationSet when a rename in the EntityDesigner is propagated // to the database and the resulting hydration events flow back up. if (associationSet == null) { var assocSetName = ModelHelper.GetUniqueName( typeof(AssociationSet), cpc.Artifact.ConceptualModel().FirstEntityContainer, Name); var cmd = new CreateAssociationSetCommand(assocSetName, CreatedAssociation); CommandProcessor.InvokeSingleCommand(cpc, cmd); associationSet = cmd.AssociationSet; } if (associationSet != null && principal.Type.Status == BindingStatus.Known && dependent.Type.Status == BindingStatus.Known && associationSet.PrincipalEnd != null && associationSet.DependentEnd != null) { associationSet.PrincipalEnd.Role.SetRefName(principal); associationSet.PrincipalEnd.EntitySet.SetRefName(principal.Type.Target.EntitySet); associationSet.DependentEnd.Role.SetRefName(dependent); associationSet.DependentEnd.EntitySet.SetRefName(dependent.Type.Target.EntitySet); XmlModelHelper.NormalizeAndResolve(associationSet); } var navProp1 = principal.GetAntiDependenciesOfType <NavigationProperty>() .FirstOrDefault(np => np.FromRole.Target == principal); if (navProp1 != null && ShouldCreateNavigationPropertyEnd1) { navProp1.Name.Value = NavigationPropertyInEnd1Entity; } var navProp2 = dependent.GetAntiDependenciesOfType <NavigationProperty>() .FirstOrDefault(np => np.FromRole.Target == dependent); if (navProp2 != null && ShouldCreateNavigationPropertyEnd2) { navProp2.Name.Value = NavigationPropertyInEnd2Entity; } } } }
protected override void InvokeInternal(CommandProcessorContext cpc) { var service = cpc.EditingContext.GetEFArtifactService(); var artifact = service.Artifact; // the model that we want to add the association to var model = artifact.ConceptualModel(); // check for uniqueness of the assocation and association set names // if uniquifyNames is true then make them unique, otherwise throw // an exception if they're not (always uniquify associationSetName // regardless as we get bugs if not) var assocName = Name; var assocSetName = assocName; if (UniquifyNames) { assocName = ModelHelper.GetUniqueName(typeof(Association), model, assocName); assocSetName = ModelHelper.GetUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocName); // ensure unique NavigationProperty names if (ShouldCreateNavigationPropertyEnd1 && !ModelHelper.IsUniquePropertyName(End1Entity, NavigationPropertyInEnd1Entity, true) || NavigationPropertyInEnd1Entity == End1Entity.LocalName.Value) { var namesToAvoid = new HashSet<string>(); namesToAvoid.Add(End1Entity.LocalName.Value); namesToAvoid.Add(NavigationPropertyInEnd2Entity); NavigationPropertyInEnd1Entity = ModelHelper.GetUniqueConceptualPropertyName( NavigationPropertyInEnd1Entity, End1Entity, namesToAvoid); } if (ShouldCreateNavigationPropertyEnd2 && !ModelHelper.IsUniquePropertyName(End2Entity, NavigationPropertyInEnd2Entity, true) || NavigationPropertyInEnd2Entity == End2Entity.LocalName.Value) { var namesToAvoid = new HashSet<string> { End2Entity.LocalName.Value, NavigationPropertyInEnd1Entity }; NavigationPropertyInEnd2Entity = ModelHelper.GetUniqueConceptualPropertyName( NavigationPropertyInEnd2Entity, End2Entity, namesToAvoid); } } else { assocSetName = ModelHelper.GetUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocName); string msg = null; if (!ModelHelper.IsUniqueName(typeof(Association), model, assocName, false, out msg)) { throw new InvalidOperationException(msg); } else if (!ModelHelper.IsUniqueName(typeof(AssociationSet), model.FirstEntityContainer, assocSetName, false, out msg)) { throw new InvalidOperationException(msg); } else if (ShouldCreateNavigationPropertyEnd1 && (!ModelHelper.IsUniquePropertyName(End1Entity, NavigationPropertyInEnd1Entity, true))) { msg = string.Format(CultureInfo.CurrentCulture, Resources.NAME_NOT_UNIQUE, NavigationPropertyInEnd1Entity); throw new InvalidOperationException(msg); } else if (ShouldCreateNavigationPropertyEnd2 && (!ModelHelper.IsUniquePropertyName(End2Entity, NavigationPropertyInEnd2Entity, true))) { msg = string.Format(CultureInfo.CurrentCulture, Resources.NAME_NOT_UNIQUE, NavigationPropertyInEnd2Entity); throw new InvalidOperationException(msg); } else if (NavigationPropertyInEnd1Entity == End1Entity.LocalName.Value) { msg = string.Format( CultureInfo.CurrentCulture, Resources.NavPropNameSameAsContainer, NavigationPropertyInEnd1Entity); throw new InvalidOperationException(msg); } else if (NavigationPropertyInEnd2Entity == End2Entity.LocalName.Value) { msg = string.Format( CultureInfo.CurrentCulture, Resources.NavPropNameSameAsContainer, NavigationPropertyInEnd2Entity); throw new InvalidOperationException(msg); } } // create the new item in our model var association = new Association(model, null); association.LocalName.Value = assocName; model.AddAssociation(association); XmlModelHelper.NormalizeAndResolve(association); // create the first end _end1 = new AssociationEnd(association, null); _end1.Type.SetRefName(End1Entity); _end1.Role.Value = End1Entity.LocalName.Value; _end1.Multiplicity.Value = End1Multiplicity; association.AddAssociationEnd(_end1); XmlModelHelper.NormalizeAndResolve(_end1); // create the second end _end2 = new AssociationEnd(association, null); _end2.Type.SetRefName(End2Entity); var endRoleValue = End2Entity.LocalName.Value; if (_end1.Role.Value.Equals(endRoleValue)) { // avoid duplicate Role values between the two ends. This will occur in self-associations. // Appending "1" is consistent with how model-gen chooses a unique name. endRoleValue = endRoleValue + "1"; } _end2.Role.Value = endRoleValue; _end2.Multiplicity.Value = End2Multiplicity; association.AddAssociationEnd(_end2); XmlModelHelper.NormalizeAndResolve(_end2); // create the association set for this association var cmd = new CreateAssociationSetCommand(assocSetName, association); CommandProcessor.InvokeSingleCommand(cpc, cmd); var set = cmd.AssociationSet; Debug.Assert(set != null, "unable to create association set"); CreateNavigationPropertyCommand navcmd; if (ShouldCreateNavigationPropertyEnd1) { navcmd = new CreateNavigationPropertyCommand(NavigationPropertyInEnd1Entity, End1Entity, association, _end1, _end2); CommandProcessor.InvokeSingleCommand(cpc, navcmd); } if (ShouldCreateNavigationPropertyEnd2) { navcmd = new CreateNavigationPropertyCommand(NavigationPropertyInEnd2Entity, End2Entity, association, _end2, _end1); CommandProcessor.InvokeSingleCommand(cpc, navcmd); } if (ShouldCreateForeignKeyProperties) { CreateForeignKeyProperties.AddRule(cpc, association); } CreatedAssociation = association; }
protected override void InvokeInternal(CommandProcessorContext cpc) { CreatedAssociation = ModelHelper.FindAssociation(cpc.Artifact.ConceptualModel(), Name); if (CreatedAssociation == null) { // This Association does not exist, create it base.InvokeInternal(cpc); } else { // The Association already exists, update it Debug.Assert( CreatedAssociation.AssociationEnds().Count == 2, "Association element is invalid, it should always have exactly 2 ends"); if (CreatedAssociation.AssociationEnds().Count == 2) { AssociationEnd principal; AssociationEnd dependent; ModelHelper.DeterminePrincipalDependentEndsForAnyAssociationType(CreatedAssociation, out principal, out dependent); if (principal.Type.Target == null || !string.Equals(principal.Type.Target.Name.Value, End1Entity.LocalName.Value, StringComparison.Ordinal)) { principal.Type.SetRefName(End1Entity); principal.Role.Value = End1Entity.LocalName.Value; } if (dependent.Type.Target == null || !string.Equals(dependent.Type.Target.Name.Value, End2Entity.LocalName.Value, StringComparison.Ordinal)) { dependent.Type.SetRefName(End2Entity); var endRoleValue = End2Entity.LocalName.Value; if (principal.Role.Value.Equals(endRoleValue)) { // avoid duplicate Role values between the two ends. This will occur in self-associations. // Appending "1" is consistent with how model-gen chooses a unique name. endRoleValue = endRoleValue + "1"; } dependent.Role.Value = endRoleValue; } if (!string.Equals(principal.Multiplicity.Value, End1Multiplicity, StringComparison.Ordinal)) { principal.Multiplicity.Value = End1Multiplicity; } if (!string.Equals(dependent.Multiplicity.Value, End2Multiplicity, StringComparison.Ordinal)) { dependent.Multiplicity.Value = End2Multiplicity; } // We have to resolve the association after both the principal and dependent have been updated here. The reason is because // if we resolve the principal and dependent separately we will end up with duplicate symbols in the symbol table because // the previous end didn't get removed. XmlModelHelper.NormalizeAndResolve(CreatedAssociation); // Also update the AssociationSet var associationSet = CreatedAssociation.AssociationSet; // It's possible for the association to exist but not the associationSet when a rename in the EntityDesigner is propagated // to the database and the resulting hydration events flow back up. if (associationSet == null) { var assocSetName = ModelHelper.GetUniqueName( typeof(AssociationSet), cpc.Artifact.ConceptualModel().FirstEntityContainer, Name); var cmd = new CreateAssociationSetCommand(assocSetName, CreatedAssociation); CommandProcessor.InvokeSingleCommand(cpc, cmd); associationSet = cmd.AssociationSet; } if (associationSet != null && principal.Type.Status == BindingStatus.Known && dependent.Type.Status == BindingStatus.Known && associationSet.PrincipalEnd != null && associationSet.DependentEnd != null) { associationSet.PrincipalEnd.Role.SetRefName(principal); associationSet.PrincipalEnd.EntitySet.SetRefName(principal.Type.Target.EntitySet); associationSet.DependentEnd.Role.SetRefName(dependent); associationSet.DependentEnd.EntitySet.SetRefName(dependent.Type.Target.EntitySet); XmlModelHelper.NormalizeAndResolve(associationSet); } var navProp1 = principal.GetAntiDependenciesOfType<NavigationProperty>() .FirstOrDefault(np => np.FromRole.Target == principal); if (navProp1 != null && ShouldCreateNavigationPropertyEnd1) { navProp1.Name.Value = NavigationPropertyInEnd1Entity; } var navProp2 = dependent.GetAntiDependenciesOfType<NavigationProperty>() .FirstOrDefault(np => np.FromRole.Target == dependent); if (navProp2 != null && ShouldCreateNavigationPropertyEnd2) { navProp2.Name.Value = NavigationPropertyInEnd2Entity; } } } }