internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator, 
                ExtractedStateEntry stateEntry)
            {
                var mapping = GetFunctionMapping(stateEntry);
                StorageEntityTypeModificationFunctionMapping typeMapping = mapping.Item1;
                StorageModificationFunctionMapping functionMapping = mapping.Item2;
                EntityKey entityKey = stateEntry.Source.EntityKey;

                var stateEntries = new HashSet<IEntityStateEntry> { stateEntry.Source };

                // gather all referenced association ends
                var collocatedEntries =
                    // find all related entries corresponding to collocated association types
                    from end in functionMapping.CollocatedAssociationSetEnds
                    join candidateEntry in translator.GetRelationships(entityKey)
                    on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType
                    select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry);

                var currentReferenceEnds = new Dictionary<AssociationEndMember, IEntityStateEntry>();
                var originalReferenceEnds = new Dictionary<AssociationEndMember, IEntityStateEntry>();

                foreach (var candidate in collocatedEntries)
                {
                    ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2);
                }
                
                // create function object
                FunctionUpdateCommand command;

                // consider the following scenario, we need to loop through all the state entries that is correlated with entity2 and make sure it is not changed.
                // entity1 <-- Independent Association <-- entity2 <-- Fk association <-- entity 3
                //                                           |
                //              entity4 <-- Fk association <--
                if (stateEntries.All(e => e.State == EntityState.Unchanged))
                {
                    // we shouldn't update the entity if it is unchanged, only update when referenced association is changed.
                    // if not, then this will trigger a fake update for principal end as describe in bug 894569.
                    command = null;
                }
                else
                {
                    command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry);

                    // bind all function parameters
                    BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds);

                    // interpret all result bindings
                    if (null != functionMapping.ResultBindings)
                    {
                        foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings)
                        {
                            PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property);
                            command.AddResultColumn(translator, resultBinding.ColumnName, result);
                        }
                    }
                }

                return command;
            }
        protected FunctionUpdateCommand(
            UpdateTranslator translator, ReadOnlyCollection<IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry,
            DbCommand dbCommand)
            : base(translator, stateEntry.Original, stateEntry.Current)
        {
            // populate the main state entry for error reporting
            _stateEntries = stateEntries;

            _dbCommand = dbCommand;
        }
 /// <summary>
 /// Initialize a new function command. Initializes the command object.
 /// </summary>
 /// <param name="functionMapping">Function mapping metadata</param>
 /// <param name="translator">Translator</param>
 /// <param name="stateEntries">State entries handled by this operation.</param>
 /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
 internal FunctionUpdateCommand(
     StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
     ReadOnlyCollection<IEntityStateEntry> stateEntries, ExtractedStateEntry stateEntry)
     : this(translator, stateEntries, stateEntry,
         translator.GenerateCommandDefinition(functionMapping).CreateCommand())
 {
     //Contract.Requires(functionMapping != null);
     //Contract.Requires(translator != null);
     //Contract.Requires(stateEntries != null);
 }
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry)
            {
                if (null == m_mapping)
                {
                    return(null);
                }

                bool isInsert = EntityState.Added == stateEntry.State;

                EntityUtil.ValidateNecessaryModificationFunctionMapping(
                    isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping,
                    isInsert ? "Insert" : "Delete",
                    stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name);

                // initialize a new command
                StorageModificationFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping;
                FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry);

                // extract the relationship values from the state entry
                PropagatorResult recordResult;

                if (isInsert)
                {
                    recordResult = stateEntry.Current;
                }
                else
                {
                    recordResult = stateEntry.Original;
                }

                // bind parameters
                foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    // extract the relationship information
                    Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " +
                                 "path should include the relationship end and key property only");

                    EdmProperty          keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                    AssociationEndMember endMember   = (AssociationEndMember)parameterBinding.MemberPath.Members[1];

                    // get the end member
                    PropagatorResult endResult = recordResult.GetMemberValue(endMember);
                    PropagatorResult keyResult = endResult.GetMemberValue(keyProperty);

                    command.SetParameterValue(keyResult, parameterBinding, translator);
                }
                // add rows affected output parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);

                return(command);
            }
        /// <summary>
        /// Initialize a new function command. Initializes the command object.
        /// </summary>
        /// <param name="functionMapping">Function mapping metadata</param>
        /// <param name="translator">Translator</param>
        /// <param name="stateEntries">State entries handled by this operation.</param>
        /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
        internal FunctionUpdateCommand(StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
            System.Collections.ObjectModel.ReadOnlyCollection<IEntityStateEntry> stateEntries,
            ExtractedStateEntry stateEntry)
            : base(stateEntry.Original, stateEntry.Current)
        {
            EntityUtil.CheckArgumentNull(functionMapping, "functionMapping");
            EntityUtil.CheckArgumentNull(translator, "translator");
            EntityUtil.CheckArgumentNull(stateEntries, "stateEntries");

            // populate the main state entry for error reporting
            m_stateEntries = stateEntries;

            // create a command
            DbCommandDefinition commandDefinition = translator.GenerateCommandDefinition(functionMapping);
            m_dbCommand = commandDefinition.CreateCommand();
        }
        /// <summary>
        /// Initialize a new function command. Initializes the command object.
        /// </summary>
        /// <param name="functionMapping">Function mapping metadata</param>
        /// <param name="translator">Translator</param>
        /// <param name="stateEntries">State entries handled by this operation.</param>
        /// <param name="stateEntry">'Root' state entry being handled by this function.</param>
        internal FunctionUpdateCommand(StorageModificationFunctionMapping functionMapping, UpdateTranslator translator,
                                       System.Collections.ObjectModel.ReadOnlyCollection <IEntityStateEntry> stateEntries,
                                       ExtractedStateEntry stateEntry)
            : base(stateEntry.Original, stateEntry.Current)
        {
            EntityUtil.CheckArgumentNull(functionMapping, "functionMapping");
            EntityUtil.CheckArgumentNull(translator, "translator");
            EntityUtil.CheckArgumentNull(stateEntries, "stateEntries");

            // populate the main state entry for error reporting
            m_stateEntries = stateEntries;

            // create a command
            DbCommandDefinition commandDefinition = translator.GenerateCommandDefinition(functionMapping);

            m_dbCommand = commandDefinition.CreateCommand();
        }
        private void LoadStateEntry(IEntityStateEntry stateEntry)
        {
            Debug.Assert(null != stateEntry, "state entry must exist");

            // make sure the state entry doesn't contain invalid data and register it with the
            // update pipeline
            ValidateAndRegisterStateEntry(stateEntry);

            // use data structure internal to the update pipeline instead of the raw state entry
            ExtractedStateEntry extractedStateEntry = new ExtractedStateEntry(this, stateEntry);

            // figure out if this state entry is being handled by a function (stored procedure) or
            // through dynamic SQL
            EntitySetBase extent = stateEntry.EntitySet;
            if (null == m_viewLoader.GetFunctionMappingTranslator(extent, m_metadataWorkspace))
            {
                // if there is no function mapping, register a ChangeNode (used for update
                // propagation and dynamic SQL generation)
                ChangeNode changeNode = GetExtentModifications(extent);
                if (null != extractedStateEntry.Original)
                {
                    changeNode.Deleted.Add(extractedStateEntry.Original);
                }
                if (null != extractedStateEntry.Current)
                {
                    changeNode.Inserted.Add(extractedStateEntry.Current);
                }
            }
            else
            {
                // for function updates, store off the extracted state entry in its entirety
                // (used when producing FunctionUpdateCommands)
                List<ExtractedStateEntry> functionEntries = GetExtentFunctionModifications(extent);
                functionEntries.Add(extractedStateEntry);
            }
        }
 /// <summary>
 /// Requires: this translator must be registered to handle the entity set
 /// for the given state entry.
 /// 
 /// Translates the given state entry to a command.
 /// </summary>
 /// <param name="translator">Parent update translator (global state for the workload)</param>
 /// <param name="stateEntry">State entry to translate. Must belong to the 
 /// entity/association set handled by this translator</param>
 /// <returns>Command corresponding to the given state entry</returns>
 internal abstract FunctionUpdateCommand Translate(
     UpdateTranslator translator,
     ExtractedStateEntry stateEntry);
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator, 
                ExtractedStateEntry stateEntry)
            {
                if (null == m_mapping) { return null; }

                bool isInsert = EntityState.Added == stateEntry.State;

                EntityUtil.ValidateNecessaryModificationFunctionMapping(
                    isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping, 
                    isInsert ? "Insert" : "Delete", 
                    stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name);

                // initialize a new command
                StorageModificationFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping;
                FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry);

                // extract the relationship values from the state entry
                PropagatorResult recordResult;
                if (isInsert) 
                {
                    recordResult = stateEntry.Current;
                }
                else 
                { 
                    recordResult = stateEntry.Original; 
                }

                // bind parameters
                foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    // extract the relationship information
                    Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " +
                        "path should include the relationship end and key property only");

                    EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                    AssociationEndMember endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1];

                    // get the end member
                    PropagatorResult endResult = recordResult.GetMemberValue(endMember);
                    PropagatorResult keyResult = endResult.GetMemberValue(keyProperty);

                    command.SetParameterValue(keyResult, parameterBinding, translator);
                }
                // add rows affected output parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);

                return command;
            }
            // Walks through all parameter bindings in the function mapping and binds the parameters to the
            // requested properties of the given state entry.
            private void BindFunctionParameters(UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageModificationFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary<AssociationEndMember, IEntityStateEntry> currentReferenceEnds, Dictionary<AssociationEndMember, IEntityStateEntry> originalReferenceEnds)
            {
                // bind all parameters
                foreach (StorageModificationFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    PropagatorResult result;

                    // extract value
                    if (null != parameterBinding.MemberPath.AssociationSetEnd)
                    {
                        // find the relationship entry corresponding to the navigation
                        AssociationEndMember endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember;
                        IEntityStateEntry relationshipEntry;
                        bool hasTarget = parameterBinding.IsCurrent
                            ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry)
                            : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry);
                        if (!hasTarget)
                        {
                            if (endMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
                            {
                                string entitySetName = stateEntry.Source.EntitySet.Name;
                                string associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name;
                                throw EntityUtil.Update(Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName),
                                    null,
                                    command.GetStateEntries(translator));
                            }
                            else
                            {
                                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null);
                            }
                        }
                        else
                        {
                            // get the actual value
                            PropagatorResult relationshipResult = parameterBinding.IsCurrent ?
                                translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified) :
                                translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified);
                            PropagatorResult endResult = relationshipResult.GetMemberValue(endMember);
                            EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0]; 
                            result = endResult.GetMemberValue(keyProperty);
                        }
                    }
                    else
                    {
                        // walk through the member path to find the appropriate propagator results
                        result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original;
                        for (int i = parameterBinding.MemberPath.Members.Count; i > 0;)
                        {
                            --i;
                            EdmMember member = parameterBinding.MemberPath.Members[i];
                            result = result.GetMemberValue(member);
                        }
                    }

                    // create DbParameter
                    command.SetParameterValue(result, parameterBinding, translator);
                }
                // Add rows affected parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
            }
 private Tuple<StorageEntityTypeModificationFunctionMapping, StorageModificationFunctionMapping> GetFunctionMapping(ExtractedStateEntry stateEntry)
 {
     // choose mapping based on type and operation
     StorageModificationFunctionMapping functionMapping;
     EntityType entityType;
     if (null != stateEntry.Current)
     {
         entityType = (EntityType)stateEntry.Current.StructuralType;
     }
     else
     {
         entityType = (EntityType)stateEntry.Original.StructuralType;
     }
     StorageEntityTypeModificationFunctionMapping typeMapping = m_typeMappings[entityType];
     switch (stateEntry.State)
     {
         case EntityState.Added:
             functionMapping = typeMapping.InsertFunctionMapping;
             EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Insert", stateEntry.Source, "EntityType", entityType.Name);
             break;
         case EntityState.Deleted:
             functionMapping = typeMapping.DeleteFunctionMapping;
             EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Delete", stateEntry.Source, "EntityType", entityType.Name);
             break;
         case EntityState.Unchanged:
         case EntityState.Modified:
             functionMapping = typeMapping.UpdateFunctionMapping;
             EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Update", stateEntry.Source, "EntityType", entityType.Name);
             break;
         default:
             functionMapping = null;
             Debug.Fail("unexpected state");
             break;
     }
     return Tuple.Create(typeMapping, functionMapping);
 }
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry)
            {
                var mapping = GetFunctionMapping(stateEntry);
                StorageEntityTypeModificationFunctionMapping typeMapping     = mapping.Item1;
                StorageModificationFunctionMapping           functionMapping = mapping.Item2;
                EntityKey entityKey = stateEntry.Source.EntityKey;

                var stateEntries = new HashSet <IEntityStateEntry> {
                    stateEntry.Source
                };

                // gather all referenced association ends
                var collocatedEntries =
                    // find all related entries corresponding to collocated association types
                    from end in functionMapping.CollocatedAssociationSetEnds
                    join candidateEntry in translator.GetRelationships(entityKey)
                    on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType
                    select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry);

                var currentReferenceEnds  = new Dictionary <AssociationEndMember, IEntityStateEntry>();
                var originalReferenceEnds = new Dictionary <AssociationEndMember, IEntityStateEntry>();

                foreach (var candidate in collocatedEntries)
                {
                    ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2);
                }

                // create function object
                FunctionUpdateCommand command;

                // consider the following scenario, we need to loop through all the state entries that is correlated with entity2 and make sure it is not changed.
                // entity1 <-- Independent Association <-- entity2 <-- Fk association <-- entity 3
                //                                           |
                //              entity4 <-- Fk association <--
                if (stateEntries.All(e => e.State == EntityState.Unchanged))
                {
                    // we shouldn't update the entity if it is unchanged, only update when referenced association is changed.
                    // if not, then this will trigger a fake update for principal end as describe in
                    command = null;
                }
                else
                {
                    command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry);

                    // bind all function parameters
                    BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds);

                    // interpret all result bindings
                    if (null != functionMapping.ResultBindings)
                    {
                        foreach (StorageModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings)
                        {
                            PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property);
                            command.AddResultColumn(translator, resultBinding.ColumnName, result);
                        }
                    }
                }

                return(command);
            }
 /// <summary>
 /// Requires: this translator must be registered to handle the entity set
 /// for the given state entry.
 ///
 /// Translates the given state entry to a command.
 /// </summary>
 /// <param name="translator">Parent update translator (global state for the workload)</param>
 /// <param name="stateEntry">State entry to translate. Must belong to the
 /// entity/association set handled by this translator</param>
 /// <returns>Command corresponding to the given state entry</returns>
 internal abstract FunctionUpdateCommand Translate(
     UpdateTranslator translator,
     ExtractedStateEntry stateEntry);
            private Tuple <StorageEntityTypeModificationFunctionMapping, StorageModificationFunctionMapping> GetFunctionMapping(ExtractedStateEntry stateEntry)
            {
                // choose mapping based on type and operation
                StorageModificationFunctionMapping functionMapping;
                EntityType entityType;

                if (null != stateEntry.Current)
                {
                    entityType = (EntityType)stateEntry.Current.StructuralType;
                }
                else
                {
                    entityType = (EntityType)stateEntry.Original.StructuralType;
                }
                StorageEntityTypeModificationFunctionMapping typeMapping = m_typeMappings[entityType];

                switch (stateEntry.State)
                {
                case EntityState.Added:
                    functionMapping = typeMapping.InsertFunctionMapping;
                    EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Insert", stateEntry.Source, "EntityType", entityType.Name);
                    break;

                case EntityState.Deleted:
                    functionMapping = typeMapping.DeleteFunctionMapping;
                    EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Delete", stateEntry.Source, "EntityType", entityType.Name);
                    break;

                case EntityState.Unchanged:
                case EntityState.Modified:
                    functionMapping = typeMapping.UpdateFunctionMapping;
                    EntityUtil.ValidateNecessaryModificationFunctionMapping(functionMapping, "Update", stateEntry.Source, "EntityType", entityType.Name);
                    break;

                default:
                    functionMapping = null;
                    Debug.Fail("unexpected state");
                    break;
                }
                return(Tuple.Create(typeMapping, functionMapping));
            }