public MappingAssociation(EditingContext context, Association assoc, MappingEFElement parent)
     : base(context, assoc, parent)
 {
     Debug.Assert(assoc != null, "MappingAssociation cannot accept a null Association");
     Debug.Assert(
         assoc.AssociationSet != null,
         "MappingAssociation cannot accept an Association " + assoc.ToPrettyString() + " with a null AssociationSet");
 }
            AddAssociationSetMappingForConceptualAssociation(
            CommandProcessorContext cpc, EFArtifact existingArtifact,
            Association assocInTempArtifact, Association assocInExistingArtifact,
            Dictionary<EntityType, EntityType> tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact)
        {
            // first find the AssociationSetMapping in the tempArtifact for this association
            var asmInTempArtifact =
                ModelHelper.FindAssociationSetMappingForConceptualAssociation(assocInTempArtifact);
            if (asmInTempArtifact == null)
            {
                if (!EdmFeatureManager.GetForeignKeysInModelFeatureState(existingArtifact.SchemaVersion).IsEnabled()
                    || assocInTempArtifact.IsManyToMany)
                {
                    // this is an error condition - we should have an association set mapping in this case, so assert and throw an exception
                    throw new UpdateModelFromDatabaseException(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resources.UpdateFromDatabaseAssociationSetMappingCannotFind,
                            assocInTempArtifact.ToPrettyString()));
                }
                else
                {
                    // we don't expect an association set mapping here
                    return;
                }
            }

            // next find the S-side EntitySet in the tempArtifact for this AssociationSetMapping
            var storeEntitySetInTempArtifact = asmInTempArtifact.StoreEntitySet.Target;
            if (storeEntitySetInTempArtifact == null)
            {
                throw new UpdateModelFromDatabaseException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.UpdateFromDatabaseAssociationSetMappingCannotFindTempSSideEntitySet,
                        asmInTempArtifact.ToPrettyString()));
            }

            // now find the S-side EntitySet in the existingArtifact which matches this
            // Note: LocalName's will be the same as the SSDL has been replaced
            StorageEntitySet storeEntitySetInExistingArtifact = null;
            foreach (var es in existingArtifact.StorageModel().FirstEntityContainer.EntitySets())
            {
                if (es.LocalName.Value == storeEntitySetInTempArtifact.LocalName.Value)
                {
                    storeEntitySetInExistingArtifact = es as StorageEntitySet;
                    break;
                }
            }

            if (storeEntitySetInExistingArtifact == null)
            {
                throw new UpdateModelFromDatabaseException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.UpdateFromDatabaseAssociationSetMappingCannotFindMatchingSSideEntitySet,
                        storeEntitySetInTempArtifact.LocalName.Value));
            }

            // now create a new AssociationSetMapping in the existingArtifact using the data
            // accumulated above
            CloneAssociationSetMapping(
                cpc,
                asmInTempArtifact,
                existingArtifact.MappingModel().FirstEntityContainerMapping,
                assocInExistingArtifact.AssociationSet,
                assocInExistingArtifact,
                storeEntitySetInExistingArtifact,
                tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact
                );
        }
        private bool HasBeenReplacedByInheritanceOrSplitEntity(
            Association assoc, AssociationIdentity assocId,
            Dictionary<EntityType, EntityType> tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact)
        {
            if (2 != assoc.AssociationEnds().Count)
            {
                Debug.Fail(
                    "Received incorrect number of AssociationEnds (" + assoc.AssociationEnds().Count + ") for Association "
                    + assoc.ToPrettyString() + " should be 2.");
                return false;
            }

            // check 1:1 or 1:0..1
            var assocEnds = assoc.AssociationEnds();
            var assocEnd1 = assocEnds[0];
            var assocEnd2 = assocEnds[1];
            if (!(ModelConstants.Multiplicity_One == assocEnd1.Multiplicity.Value
                  && (ModelConstants.Multiplicity_One == assocEnd2.Multiplicity.Value ||
                      ModelConstants.Multiplicity_ZeroOrOne == assocEnd2.Multiplicity.Value))
                ||
                (ModelConstants.Multiplicity_One == assocEnd2.Multiplicity.Value
                 && (ModelConstants.Multiplicity_One == assocEnd1.Multiplicity.Value ||
                     ModelConstants.Multiplicity_ZeroOrOne == assocEnd1.Multiplicity.Value)))
            {
                return false;
            }

            // get C-side EntityTypes for each AssociationEnd
            var et1 = assocEnd1.Type.Target as ConceptualEntityType;
            var et2 = assocEnd2.Type.Target as ConceptualEntityType;
            if (null == et1)
            {
                Debug.Fail("EntityType et1 is not a ConceptualEntityType");
                return false;
            }
            else if (null == et2)
            {
                Debug.Fail("EntityType et2 is not a ConceptualEntityType");
                return false;
            }

            // check not both pointing to same entity type (i.e. self-association)
            if (et1.Equals(et2))
            {
                return false;
            }

            // check inheritance relationship

            // First identify the association table and which end 
            // contains that table
            var et1Id = _modelRepresentingDatabase.GetEntityTypeIdentityForEntityType(et1);
            var et2Id = _modelRepresentingDatabase.GetEntityTypeIdentityForEntityType(et2);
            if (null == et1Id)
            {
                Debug.Fail("Could not find EntityTypeIdentity for et1 " + et1.ToPrettyString());
                return false;
            }
            else if (null == et2Id)
            {
                Debug.Fail("Could not find EntityTypeIdentity for et2 " + et2.ToPrettyString());
                return false;
            }

            EntityTypeIdentity etIdNotContainingAssocTable = null;

            var tables = assocId.AssociationTables.GetEnumerator();
            tables.MoveNext();
            var assocTable = tables.Current;

            if (tables.MoveNext())
            {
                //
                // If we get here, the properties involved in a Ref Constraint were mapped to multiple tables.  This implies inheritance 
                // or horizontal partitioning on the database (ie, the dependent end of the RC is an entity mapped to more than one table, 
                // so the RC spans tables).  
                //
                // We don't ever expect this to be the case for a model generated from model-gen APIs, so assert.  
                //
                Debug.Fail(
                    "An association is mapped to more than one table on the dependent via a referential constraint.  We didn't expect this to happen for a model generated from model gen APIs");
                // just return false here.  It should be OK for us to include this association, and the user can make the call on what to do.
                return false;
            }

            if (et1Id.ContainsDatabaseObject(assocTable))
            {
                etIdNotContainingAssocTable = et2Id;
            }
            else if (et2Id.ContainsDatabaseObject(assocTable))
            {
                etIdNotContainingAssocTable = et1Id;
            }
            else
            {
                // Neither end of a 1:1 or 1:0..1 Association contains the association table.
                // This is an error.
                Debug.Fail(
                    "Neither end of the Association " + assoc.ToPrettyString() + " contains the association table " + assocTable.ToString());
                return false;
            }

            // now find the C-side EntityTypes in the existing artifact
            // for that association table
            var existingEntityTypesForAssocTable =
                _preExistingModel.GetConceptualEntityTypesForDatabaseObject(assocTable);

            // now if any of these EntityTypes has an ancestor which maps 
            // to any of the tables/views in the EntityTypeIdentity of 
            // the _other_ AssociationEnd then we have found the inheritance
            // relationship which replaced this Association
            // Note: this covers the case where one or the other end is a new table/view:
            // if assocTable is "new" then existingEntityTypesForAssocTable will be null,
            // if the other end of the association is "new" then no existing EntityType
            // will have an ancestor type that maps to the tables/views in the other end.
            if (null != existingEntityTypesForAssocTable)
            {
                foreach (var cet in existingEntityTypesForAssocTable)
                {
                    foreach (var tableOrView in etIdNotContainingAssocTable.TablesAndViews)
                    {
                        if (_preExistingModel.HasAncestorTypeThatMapsToDbObject(cet, tableOrView))
                        {
                            return true;
                        }
                    }
                }
            }

            // check split-entity

            // find the C-Side EntityTypes in the existing artifact for both ends
            var existingEntityType1 = FindMatchingConceptualEntityTypeInExistingArtifact(
                et1,
                tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact);
            var existingEntityType2 = FindMatchingConceptualEntityTypeInExistingArtifact(
                et2,
                tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact);

            // if either there are no matching EntityTypes or the 2 matching EntityTypes
            // are different in the existing artifact then this is not split-entity
            if (null == existingEntityType1
                || null == existingEntityType2
                || !existingEntityType1.Equals(existingEntityType2))
            {
                return false;
            }

            // check referential constraint
            var refConstraint = assoc.ReferentialConstraint;
            if (null == refConstraint)
            {
                return false;
            }

            return (HasIdenticalKeyToEntityType(refConstraint.Principal)
                    && HasIdenticalKeyToEntityType(refConstraint.Dependent));
        }
        /// <summary>
        ///     Clone the Association with its ReferentialConstraint (if available), AssociationSet
        ///     and AssociationSetMapping. If the ReferentialConstraint is available in the temp artifact
        ///     but we cannot find matching properties in the existing artifact then the whole Association
        ///     (and AssociationSet and AssociationSetMapping) will not be cloned, a warning message will
        ///     be issued but otherwise the process is not stopped.
        ///     But if the Association cannot be created for any other reason that's an error and an
        ///     UpdateModelFromDatabaseException will be thrown.
        /// </summary>
        /// <param name="cpc">CommandProcessorContext for the commands to be issued</param>
        /// <param name="existingArtifact">the existing artifact in which to make these changes</param>
        /// <param name="assocInTempArtifact">the Association in the temp artifact to be cloned</param>
        /// <param name="end1InTempArtifact">the end of the Association in the temp artifact to be cloned to be treated as End1</param>
        /// <param name="end2InTempArtifact">the end of the Association in the temp artifact to be cloned to be treated as End2</param>
        /// <param name="navProp1InTempArtifact">the NavigationProperty for End1 in the temp artifact to be cloned</param>
        /// <param name="navProp2InTempArtifact">the NavigationProperty for End2 in the temp artifact to be cloned</param>
        /// <param name="end1EntityTypeInExistingArtifact">the EntityType in the existing artifact matching the End1 target in the temp artifact</param>
        /// <param name="end2EntityTypeInExistingArtifact">the EntityType in the existing artifact matching the End2 target in the temp artifact</param>
        /// <param name="tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact">
        ///     a Dictionary mapping temp artifact EntityTypes which have
        ///     been identified as new to their equivalent in the existing artifact
        /// </param>
        private void CloneAssociation(
            CommandProcessorContext cpc, EFArtifact existingArtifact, Association assocInTempArtifact,
            AssociationEnd end1InTempArtifact, AssociationEnd end2InTempArtifact,
            NavigationProperty navProp1InTempArtifact, NavigationProperty navProp2InTempArtifact,
            ConceptualEntityType end1EntityTypeInExistingArtifact, ConceptualEntityType end2EntityTypeInExistingArtifact,
            Dictionary<EntityType, EntityType> tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact)
        {
            Association newAssocInExistingArtifact = null;
            AssociationEnd newAssocEnd1 = null;
            AssociationEnd newAssocEnd2 = null;
            if (assocInTempArtifact.ReferentialConstraint == null)
            {
                // if there is no ReferentialConstraint to clone then just try to 
                // create the Association and AssociationSet
                var cmd = new CreateConceptualAssociationCommand(
                    assocInTempArtifact.LocalName.Value,
                    end1EntityTypeInExistingArtifact, end1InTempArtifact.Multiplicity.Value, navProp1InTempArtifact.LocalName.Value,
                    end2EntityTypeInExistingArtifact, end2InTempArtifact.Multiplicity.Value, navProp2InTempArtifact.LocalName.Value,
                    true, false);
                CommandProcessor.InvokeSingleCommand(cpc, cmd);
                newAssocInExistingArtifact = cmd.CreatedAssociation;
                newAssocEnd1 = cmd.End1;
                newAssocEnd2 = cmd.End2;
            }
            else
            {
                // There is a ReferentialConstraint - so we need to check whether we can find matching properties
                // for the Principal and Dependent roles of the ReferentialConstraint. If we can't find
                // matching properties then log a warning message and return. Otherwise attempt to create
                // the Association (and its AssociationSet) followed by a matching ReferentialConstraint.
                //
                // Note: ShouldCreateAssociationGivenReferentialConstraint() produces 2 sets of information:
                // (1) the sets of matching properties to use if we can find matching properties for the Principal
                // and Dependent roles, and (2) the sets of property names to include in the error message if 
                // we cannot find matching properties for the Principal and Dependent roles.
                // If ShouldCreateAssociationGivenReferentialConstraint() returns true we use the first set of
                // information to create the ReferentialConstraint after having created the Association and
                // AssociationSet. If it returns false we use the second set of information to construct the
                // warning message.
                var refConstraintInTempArtifact = assocInTempArtifact.ReferentialConstraint;
                bool end1IsPrincipalEnd;
                List<Property> principalPropertiesInExistingArtifact;
                List<Property> dependentPropertiesInExistingArtifact;
                List<string> unfoundPrincipalProperties;
                List<string> unfoundDependentProperties;
                if (ShouldCreateAssociationGivenReferentialConstraint(
                    refConstraintInTempArtifact, end1InTempArtifact,
                    end2InTempArtifact, end1EntityTypeInExistingArtifact, end2EntityTypeInExistingArtifact, out end1IsPrincipalEnd,
                    out principalPropertiesInExistingArtifact, out dependentPropertiesInExistingArtifact,
                    out unfoundPrincipalProperties, out unfoundDependentProperties))
                {
                    // create the new Association and AssociationSet
                    var cmd = new CreateConceptualAssociationCommand(
                        assocInTempArtifact.LocalName.Value,
                        end1EntityTypeInExistingArtifact, end1InTempArtifact.Multiplicity.Value, navProp1InTempArtifact.LocalName.Value,
                        end2EntityTypeInExistingArtifact, end2InTempArtifact.Multiplicity.Value, navProp2InTempArtifact.LocalName.Value,
                        true, false);
                    CommandProcessor.InvokeSingleCommand(cpc, cmd);
                    newAssocInExistingArtifact = cmd.CreatedAssociation;
                    newAssocEnd1 = cmd.End1;
                    newAssocEnd2 = cmd.End2;

                    // Add in the ReferentialConstraint for the new Association
                    if (null != newAssocInExistingArtifact)
                    {
                        AddReferentialConstraintForAssociation(
                            cpc, cmd, end1IsPrincipalEnd, principalPropertiesInExistingArtifact, dependentPropertiesInExistingArtifact);
                    }
                }
                else
                {
                    // Unable to find matching properties for the Principal and Dependent roles of 
                    // the ReferentialConstraint. So log a warning message.
                    newAssocInExistingArtifact = null;
                    EntityType principalEndEntityType = end1IsPrincipalEnd
                                                            ? end1EntityTypeInExistingArtifact
                                                            : end2EntityTypeInExistingArtifact;
                    EntityType dependentEndEntityType = end1IsPrincipalEnd
                                                            ? end2EntityTypeInExistingArtifact
                                                            : end1EntityTypeInExistingArtifact;
                    LogWarningMessageForReferentialConstraintProperties(
                        assocInTempArtifact.LocalName.Value,
                        principalEndEntityType, dependentEndEntityType, unfoundPrincipalProperties, unfoundDependentProperties);

                    // having logged the warning message we do not need to attempt to create
                    // the AssociationSetMapping nor throw an exception due to the lack of the
                    // created Association - so just return
                    return;
                }
            }

            // if we have failed to create an Association at this stage that's a serious error
            // so throw an exception to indicate the failure
            if (null == newAssocInExistingArtifact)
            {
                throw new UpdateModelFromDatabaseException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.UpdateFromDatabaseCannotCreateAssociation,
                        assocInTempArtifact.ToPrettyString()));
            }

            // update OnDeleteActions to match temp artifact
            UpdateOnDeleteAction(cpc, newAssocEnd1, end1InTempArtifact);
            UpdateOnDeleteAction(cpc, newAssocEnd2, end2InTempArtifact);

            // add a new AssociationSetMapping for the new Association
            AddAssociationSetMappingForConceptualAssociation(
                cpc, existingArtifact, assocInTempArtifact,
                newAssocInExistingArtifact, tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact);
        }