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;
            }
        internal DynamicUpdateCommand(TableChangeProcessor processor, UpdateTranslator translator, ModificationOperator op,
            PropagatorResult originalValues, PropagatorResult currentValues, DbModificationCommandTree tree,
            Dictionary<int, string> outputIdentifiers)
            : base(originalValues, currentValues)
        {
            m_processor = EntityUtil.CheckArgumentNull(processor, "processor");
            m_operator = op;
            m_modificationCommandTree = EntityUtil.CheckArgumentNull(tree, "commandTree");
            m_outputIdentifiers = outputIdentifiers; // may be null (not all commands have output identifiers)

            // initialize identifier information (supports lateral propagation of server gen values)
            if (ModificationOperator.Insert == op || ModificationOperator.Update == op)
            {
                const int capacity = 2; // "average" number of identifiers per row
                m_inputIdentifiers = new List<KeyValuePair<int ,DbSetClause>>(capacity);

                foreach (KeyValuePair<EdmMember, PropagatorResult> member in
                    Helper.PairEnumerations(TypeHelpers.GetAllStructuralMembers(this.CurrentValues.StructuralType),
                                             this.CurrentValues.GetMemberValues()))
                {
                    DbSetClause setter;
                    int identifier = member.Value.Identifier;

                    if (PropagatorResult.NullIdentifier != identifier &&
                        TryGetSetterExpression(tree, member.Key, op, out setter)) // can find corresponding setter
                    {
                        foreach (int principal in translator.KeyManager.GetPrincipals(identifier))
                        {
                            m_inputIdentifiers.Add(new KeyValuePair<int, DbSetClause>(principal, setter));
                        }
                    }
                }
            }
        }
        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);
 }
示例#5
0
        /// <summary>
        /// Finds all markup associated with the given source.
        /// </summary>
        /// <param name="source">Source expression. Must not be null.</param>
        /// <param name="translator">Translator containing session information.</param>
        /// <param name="sourceTable">Table from which the exception was thrown (must not be null).</param>
        /// <returns>Markup.</returns>
        internal static ReadOnlyCollection<IEntityStateEntry> GetAllStateEntries(PropagatorResult source, UpdateTranslator translator,
            EntitySet sourceTable)
        {
            Debug.Assert(null != source);
            Debug.Assert(null != translator);
            Debug.Assert(null != sourceTable);

            SourceInterpreter interpreter = new SourceInterpreter(translator, sourceTable);
            interpreter.RetrieveResultMarkup(source);

            return new ReadOnlyCollection<IEntityStateEntry>(interpreter.m_stateEntries);
        }
        /// <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>
                /// Construct a new placeholder with the shape of the given placeholder. Key values are
                /// injected into the resulting place holder and default values are substituted with
                /// either propagator constants or progagator nulls depending on the mode established
                /// by the <paramref name="mode"/> flag.
                /// </summary>
                /// <remarks>
                /// The key is essentially an array of values. The key map indicates that for a particular
                /// placeholder an expression (keyMap.Keys) corresponds to some ordinal in the key array.
                /// </remarks>
                /// <param name="placeholder">Placeholder to clone</param>
                /// <param name="key">Key to substitute</param>
                /// <param name="placeholderKey">Key elements in the placeholder (ordinally aligned with 'key')</param>
                /// <param name="mode">Mode of operation.</param>
                /// <param name="translator">Translator context.</param>
                /// <returns>Cloned placeholder with key values</returns>
                internal static PropagatorResult Populate(PropagatorResult placeholder, CompositeKey key, 
                    CompositeKey placeholderKey, PopulateMode mode, UpdateTranslator translator)
                {
                    EntityUtil.CheckArgumentNull(placeholder, "placeholder");
                    EntityUtil.CheckArgumentNull(key, "key");
                    EntityUtil.CheckArgumentNull(placeholderKey, "placeholderKey");
                    EntityUtil.CheckArgumentNull(translator, "translator");

                    // Figure out which flags to apply to generated elements.
                    bool isNull = mode == PopulateMode.NullModified || mode == PopulateMode.NullPreserve;
                    bool preserve = mode == PopulateMode.NullPreserve || mode == PopulateMode.Unknown;
                    PropagatorFlags flags = PropagatorFlags.NoFlags;
                    if (!isNull) { flags |= PropagatorFlags.Unknown; } // only null values are known
                    if (preserve) { flags |= PropagatorFlags.Preserve; }

                    PropagatorResult result = placeholder.Replace(node =>
                        {
                            // See if this is a key element
                            int keyIndex = -1;
                            for (int i = 0; i < placeholderKey.KeyComponents.Length; i++)
                            {
                                if (placeholderKey.KeyComponents[i] == node)
                                {
                                    keyIndex = i;
                                    break;
                                }
                            }

                            if (keyIndex != -1)
                            {
                                // Key value.
                                return key.KeyComponents[keyIndex];
                            }
                            else
                            {
                                // for simple entries, just return using the markup context for this
                                // populator
                                object value = isNull ? null : node.GetSimpleValue();
                                return PropagatorResult.CreateSimpleValue(flags, value);
                            }
                        });
                    
                    return result;
                }
        internal DynamicUpdateCommand(
            TableChangeProcessor processor, UpdateTranslator translator,
            ModificationOperator modificationOperator, PropagatorResult originalValues, PropagatorResult currentValues,
            DbModificationCommandTree tree, Dictionary<int, string> outputIdentifiers)
            : base(translator, originalValues, currentValues)
        {
            //Contract.Requires(processor != null);
            //Contract.Requires(translator != null);
            //Contract.Requires(tree != null);

            _processor = processor;
            _operator = modificationOperator;
            _modificationCommandTree = tree;
            _outputIdentifiers = outputIdentifiers; // may be null (not all commands have output identifiers)

            // initialize identifier information (supports lateral propagation of server gen values)
            if (ModificationOperator.Insert == modificationOperator
                || ModificationOperator.Update == modificationOperator)
            {
                const int capacity = 2; // "average" number of identifiers per row
                _inputIdentifiers = new List<KeyValuePair<int, DbSetClause>>(capacity);

                foreach (var member in
                    Helper.PairEnumerations(
                        TypeHelpers.GetAllStructuralMembers(CurrentValues.StructuralType),
                        CurrentValues.GetMemberValues()))
                {
                    DbSetClause setter;
                    var identifier = member.Value.Identifier;

                    if (PropagatorResult.NullIdentifier != identifier
                        &&
                        TryGetSetterExpression(tree, member.Key, modificationOperator, out setter)) // can find corresponding setter
                    {
                        foreach (var principal in translator.KeyManager.GetPrincipals(identifier))
                        {
                            _inputIdentifiers.Add(new KeyValuePair<int, DbSetClause>(principal, setter));
                        }
                    }
                }
            }
        }
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            //Contract.Requires(translator != null);
            //Contract.Requires(stateEntry != null);

            State = stateEntry.State;
            Source = stateEntry;

            switch (stateEntry.State)
            {
                case EntityState.Deleted:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    Current = null;
                    break;
                case EntityState.Unchanged:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    break;
                case EntityState.Modified:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    break;
                case EntityState.Added:
                    Original = null;
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    break;
                default:
                    Contract.Assert(false, "Unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                    Original = null;
                    Current = null;
                    break;
            }
        }
示例#10
0
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            Debug.Assert(null != stateEntry, "stateEntry must not be null");
            this.State = stateEntry.State;
            this.Source = stateEntry;

            switch (stateEntry.State)
            {
                case EntityState.Deleted:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    this.Current = null;
                    break;
                case EntityState.Unchanged:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    break;
                case EntityState.Modified:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    break;
                case EntityState.Added:
                    this.Original = null;
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    break;
                default:
                    Debug.Fail("unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                    this.Original = null;
                    this.Current = null;
                    break;
            }
        }
 /// <summary>
 /// Initialize an update compiler.
 /// </summary>
 /// <param name="translator">Update context.</param>
 internal UpdateCompiler(UpdateTranslator translator)
 {
     m_translator = translator;
 }
        /// <summary>
        /// Persists stateManager changes to the store.
        /// </summary>
        /// <param name="stateManager">StateManager containing changes to persist.</param>
        /// <param name="adapter">Map adapter requesting the changes.</param>
        /// <returns>Total number of state entries affected</returns>
        internal static Int32 Update(IEntityStateManager stateManager, IEntityAdapter adapter)
        {
            // provider/connection details
            EntityConnection connection = (EntityConnection)adapter.Connection;
            MetadataWorkspace metadataWorkspace = connection.GetMetadataWorkspace();
            int? commandTimeout = adapter.CommandTimeout;

            UpdateTranslator translator = new UpdateTranslator(stateManager, metadataWorkspace, connection, commandTimeout);
                
            // tracks values for identifiers in this session
            Dictionary<int, object> identifierValues = new Dictionary<int, object>();

            // tracks values for generated values in this session
            List<KeyValuePair<PropagatorResult, object>> generatedValues = new List<KeyValuePair<PropagatorResult, object>>();

            IEnumerable<UpdateCommand> orderedCommands = translator.ProduceCommands();

            // used to track the source of commands being processed in case an exception is thrown
            UpdateCommand source = null;
            try
            {
                foreach (UpdateCommand command in orderedCommands)
                {
                    // Remember the data sources so that we can throw meaningful exception
                    source = command;
                    long rowsAffected = command.Execute(translator, connection, identifierValues, generatedValues);
                    translator.ValidateRowsAffected(rowsAffected, source);
                }
            }
            catch (Exception e)
            {
                // we should not be wrapping all exceptions
                if (UpdateTranslator.RequiresContext(e))
                {
                    throw EntityUtil.Update(System.Data.Entity.Strings.Update_GeneralExecutionException, e, translator.DetermineStateEntriesFromSource(source));
                }
                throw;
            }

            translator.BackPropagateServerGen(generatedValues);

            int totalStateEntries = translator.AcceptChanges(adapter);

            return totalStateEntries;
        }
 private SourceInterpreter(UpdateTranslator translator, EntitySet sourceTable)
 {
     m_stateEntries = new List<IEntityStateEntry>();
     m_translator = translator;
     m_sourceTable = sourceTable;
 }
示例#14
0
        internal override long Execute(UpdateTranslator translator, EntityConnection connection, Dictionary<int, object> identifierValues, List<KeyValuePair<PropagatorResult, object>> generatedValues)
        {
            // Compile command
            using (DbCommand command = this.CreateCommand(translator, identifierValues))
            {
                // configure command to use the connection and transaction for this session
                command.Transaction = ((null != connection.CurrentTransaction) ? connection.CurrentTransaction.StoreTransaction : null);
                command.Connection = connection.StoreConnection;
                if (translator.CommandTimeout.HasValue)
                {
                    command.CommandTimeout = translator.CommandTimeout.Value;
                }

                // Execute the query
                int rowsAffected;
                if (m_modificationCommandTree.HasReader)
                {
                    // retrieve server gen results
                    rowsAffected = 0;
                    using (DbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
                    {
                        if (reader.Read())
                        {
                            rowsAffected++;

                            IBaseList<EdmMember> members = TypeHelpers.GetAllStructuralMembers(this.CurrentValues.StructuralType);

                            for (int ordinal = 0; ordinal < reader.FieldCount; ordinal++)
                            {
                                // column name of result corresponds to column name of table
                                string columnName = reader.GetName(ordinal);
                                EdmMember member = members[columnName];
                                object value;
                                if (Helper.IsSpatialType(member.TypeUsage) && !reader.IsDBNull(ordinal))
                                {
                                    value = SpatialHelpers.GetSpatialValue(translator.MetadataWorkspace, reader, member.TypeUsage, ordinal);
                                }
                                else
                                {
                                    value = reader.GetValue(ordinal);
                                }

                                // retrieve result which includes the context for back-propagation
                                int columnOrdinal = members.IndexOf(member);
                                PropagatorResult result = this.CurrentValues.GetMemberValue(columnOrdinal);

                                // register for back-propagation
                                generatedValues.Add(new KeyValuePair<PropagatorResult, object>(result, value));

                                // register identifier if it exists
                                int identifier = result.Identifier;
                                if (PropagatorResult.NullIdentifier != identifier)
                                {
                                    identifierValues.Add(identifier, value);
                                }
                            }
                        }

                        // Consume the current reader (and subsequent result sets) so that any errors
                        // executing the command can be intercepted
                        CommandHelper.ConsumeReader(reader);
                    }
                }
                else
                {
                    rowsAffected = command.ExecuteNonQuery();
                }

                return rowsAffected;
            }
        }
示例#15
0
        internal override IList<IEntityStateEntry> GetStateEntries(UpdateTranslator translator)
        {
            List<IEntityStateEntry> stateEntries = new List<IEntityStateEntry>(2);
            if (null != this.OriginalValues)
            {
                foreach (IEntityStateEntry stateEntry in SourceInterpreter.GetAllStateEntries(
                    this.OriginalValues, translator, this.Table))
                {
                    stateEntries.Add(stateEntry);
                }
            }

            if (null != this.CurrentValues)
            {
                foreach (IEntityStateEntry stateEntry in SourceInterpreter.GetAllStateEntries(
                    this.CurrentValues, translator, this.Table))
                {
                    stateEntries.Add(stateEntry);
                }
            }
            return stateEntries;
        }
            /// <summary>
            /// Creates a record for an extent containing default values. Assumes the extent is either
            /// a relationship set or an entity set.
            /// </summary>
            /// <remarks>
            /// Each scalar value appearing in the record is a <see cref="DbConstantExpression" />. A placeholder is created by recursively
            /// building a record, so an entity record type will return a new record (<see cref="DbNewInstanceExpression" />)
            /// consisting of some recursively built record for each column in the type.
            /// </remarks>
            /// <param name="extent">Extent</param>
            /// <param name="parent">Command tree used to generate portions of the record</param>
            /// <returns>A default record for the </returns>
            internal static PropagatorResult CreatePlaceholder(EntitySetBase extent, UpdateTranslator parent)
            {
                EntityUtil.CheckArgumentNull(extent, "extent");

                ExtentPlaceholderCreator creator = new ExtentPlaceholderCreator(parent);

                AssociationSet associationSet = extent as AssociationSet;
                if (null != associationSet)
                {
                    return creator.CreateAssociationSetPlaceholder(associationSet);
                }

                EntitySet entitySet = extent as EntitySet;
                if (null != entitySet)
                {
                    return creator.CreateEntitySetPlaceholder(entitySet);
                }

                throw EntityUtil.NotSupported(System.Data.Entity.Strings.Update_UnsupportedExtentType(
                    extent.Name, extent.GetType().Name));
            }
 private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName)
 {
     int columnOrdinal;
     try
     {
         columnOrdinal = reader.GetOrdinal(columnName);
     }
     catch (IndexOutOfRangeException)
     {
         throw EntityUtil.Update(System.Data.Entity.Strings.Update_MissingResultColumn(columnName), null,
             this.GetStateEntries(translator));
     }
     return columnOrdinal;
 }
        // efects: Executes the current function command in the given transaction and connection context.
        // All server-generated values are added to the generatedValues list. If those values are identifiers, they are
        // also added to the identifierValues dictionary, which associates proxy identifiers for keys in the session
        // with their actual values, permitting fix-up of identifiers across relationships.
        internal override long Execute(UpdateTranslator translator, EntityConnection connection, Dictionary<int, object> identifierValues,
            List<KeyValuePair<PropagatorResult, object>> generatedValues)
        {
            // configure command to use the connection and transaction for this session
            m_dbCommand.Transaction = ((null != connection.CurrentTransaction) ? connection.CurrentTransaction.StoreTransaction : null);
            m_dbCommand.Connection = connection.StoreConnection;
            if (translator.CommandTimeout.HasValue)
            {
                m_dbCommand.CommandTimeout = translator.CommandTimeout.Value;
            }

            // set all identifier inputs (to support propagation of identifier values across relationship
            // boundaries)
            if (null != m_inputIdentifiers)
            {
                foreach (KeyValuePair<int, DbParameter> inputIdentifier in m_inputIdentifiers)
                {
                    object value;
                    if (identifierValues.TryGetValue(inputIdentifier.Key, out value))
                    {
                        // set the actual value for the identifier if it has been produced by some
                        // other command
                        inputIdentifier.Value.Value = value;
                    }
                }
            }

            // Execute the query
            long rowsAffected;
            if (null != m_resultColumns)
            {
                // If there are result columns, read the server gen results
                rowsAffected = 0;
                IBaseList<EdmMember> members = TypeHelpers.GetAllStructuralMembers(this.CurrentValues.StructuralType);                
                using (DbDataReader reader = m_dbCommand.ExecuteReader(CommandBehavior.SequentialAccess))
                {
                    // Retrieve only the first row from the first result set
                    if (reader.Read())
                    {
                        rowsAffected++;

                        foreach (var resultColumn in m_resultColumns
                            .Select(r => new KeyValuePair<int, PropagatorResult>(GetColumnOrdinal(translator, reader, r.Key), r.Value))
                            .OrderBy(r => r.Key)) // order by column ordinal to avoid breaking SequentialAccess readers
                        {
                            int columnOrdinal = resultColumn.Key;
                            TypeUsage columnType = members[resultColumn.Value.RecordOrdinal].TypeUsage;
                            object value;

                            if (Helper.IsSpatialType(columnType) && !reader.IsDBNull(columnOrdinal))
                            {
                                value = SpatialHelpers.GetSpatialValue(translator.MetadataWorkspace, reader, columnType, columnOrdinal);
                            }
                            else
                            {
                                value = reader.GetValue(columnOrdinal);
                            }

                            // register for back-propagation
                            PropagatorResult result = resultColumn.Value;
                            generatedValues.Add(new KeyValuePair<PropagatorResult, object>(result, value));

                            // register identifier if it exists
                            int identifier = result.Identifier;
                            if (PropagatorResult.NullIdentifier != identifier)
                            {
                                identifierValues.Add(identifier, value);
                            }
                        }
                    }

                    // Consume the current reader (and subsequent result sets) so that any errors
                    // executing the function can be intercepted
                    CommandHelper.ConsumeReader(reader);
                }
            }
            else
            {
                rowsAffected = m_dbCommand.ExecuteNonQuery();
            }

            // if an explicit rows affected parameter exists, use this value instead
            if (null != m_rowsAffectedParameter)
            {
                // by design, negative row counts indicate failure iff. an explicit rows
                // affected parameter is used
                if (DBNull.Value.Equals(m_rowsAffectedParameter.Value))
                {
                    rowsAffected = 0;
                }
                else
                {
                    try
                    {
                        rowsAffected = Convert.ToInt64(m_rowsAffectedParameter.Value, CultureInfo.InvariantCulture);
                    }
                    catch (Exception e)
                    {
                        if (UpdateTranslator.RequiresContext(e))
                        {
                            // wrap the exception
                            throw EntityUtil.Update(System.Data.Entity.Strings.Update_UnableToConvertRowsAffectedParameterToInt32(
                                m_rowsAffectedParameter.ParameterName, typeof(int).FullName), e, this.GetStateEntries(translator));
                        }
                        throw;
                    }
                }
            }

            return rowsAffected;
        }
        // Adds a result column binding from a column name (from the result set for the function) to
        // a propagator result (which contains the context necessary to back-propagate the result).
        // If the result is an identifier, binds the 
        internal void AddResultColumn(UpdateTranslator translator, String columnName, PropagatorResult result)
        {
            const int initializeSize = 2; // expect on average less than two result columns per command
            if (null == m_resultColumns)
            {
                m_resultColumns = new List<KeyValuePair<string, PropagatorResult>>(initializeSize);
            }
            m_resultColumns.Add(new KeyValuePair<string, PropagatorResult>(columnName, result));

            int identifier = result.Identifier;
            if (PropagatorResult.NullIdentifier != identifier)
            {
                if (translator.KeyManager.HasPrincipals(identifier))
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_GeneratedDependent(columnName));
                }

                // register output identifier to enable fix-up and dependency tracking
                AddOutputIdentifier(columnName, identifier);
            }
        }
        // Adds and register a DbParameter to the current command.
        internal void SetParameterValue(PropagatorResult result, StorageModificationFunctionParameterBinding parameterBinding, UpdateTranslator translator)
        {
            // retrieve DbParameter
            DbParameter parameter = this.m_dbCommand.Parameters[parameterBinding.Parameter.Name];
            TypeUsage parameterType = parameterBinding.Parameter.TypeUsage;
            object parameterValue = translator.KeyManager.GetPrincipalValue(result);
            translator.SetParameterValue(parameter, parameterType, parameterValue); 

            // if the parameter corresponds to an identifier (key component), remember this fact in case
            // it's important for dependency ordering (e.g., output the identifier before creating it)
            int identifier = result.Identifier;
            if (PropagatorResult.NullIdentifier != identifier)
            {
                const int initialSize = 2; // expect on average less than two input identifiers per command
                if (null == m_inputIdentifiers)
                {
                    m_inputIdentifiers = new List<KeyValuePair<int, DbParameter>>(initialSize);
                }
                foreach (int principal in translator.KeyManager.GetPrincipals(identifier))
                {
                    m_inputIdentifiers.Add(new KeyValuePair<int, DbParameter>(principal, parameter));
                }
            }
        }
 /// <summary>
 /// Gets state entries contributing to this function. Supports error reporting.
 /// </summary>
 internal override IList<IEntityStateEntry> GetStateEntries(UpdateTranslator translator)
 {
     return m_stateEntries;
 }
 /// <summary>
 /// Initializes a new converter given a command tree context. Initializes a new record layout cache.
 /// </summary>
 /// <param name="updateTranslator">Sets <see cref="m_updateTranslator" /></param>
 internal RecordConverter(UpdateTranslator updateTranslator)
 {
     m_updateTranslator = updateTranslator;
 }
示例#23
0
        /// <summary>
        /// Gets DB command definition encapsulating store logic for this command.
        /// </summary>
        private DbCommand CreateCommand(UpdateTranslator translator, Dictionary<int, object> identifierValues)
        {
            DbModificationCommandTree commandTree = m_modificationCommandTree;

            // check if any server gen identifiers need to be set
            if (null != m_inputIdentifiers)
            {
                Dictionary<DbSetClause, DbSetClause> modifiedClauses = new Dictionary<DbSetClause, DbSetClause>();
                for (int idx = 0; idx < m_inputIdentifiers.Count; idx++)
                {
                    KeyValuePair<int, DbSetClause> inputIdentifier = m_inputIdentifiers[idx];

                    object value;
                    if (identifierValues.TryGetValue(inputIdentifier.Key, out value))
                    {
                        // reset the value of the identifier
                        DbSetClause newClause = new DbSetClause(inputIdentifier.Value.Property, DbExpressionBuilder.Constant(value));
                        modifiedClauses[inputIdentifier.Value] = newClause;
                        m_inputIdentifiers[idx] = new KeyValuePair<int, DbSetClause>(inputIdentifier.Key, newClause);
                    }
                }
                commandTree = RebuildCommandTree(commandTree, modifiedClauses);
            }

            return translator.CreateCommand(commandTree);
        }
        /// <summary>
        /// Converts a record to a propagator result
        /// </summary>
        /// <param name="stateEntry">state manager entry containing the record</param>
        /// <param name="isModified">Indicates whether the root element is modified (i.e., whether the type has changed)</param>
        /// <param name="record">Record to convert</param>
        /// <param name="useCurrentValues">Indicates whether we are retrieving current or original values.</param>
        /// <param name="translator">Translator for session context; registers new metadata for the record type if none
        /// exists</param>
        /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param>
        /// <returns>Result corresponding to the given record</returns>
        internal static PropagatorResult ExtractResultFromRecord(IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record, 
            bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            StructuralType structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType;
            ExtractorMetadata metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType);
            EntityKey key = stateEntry.EntityKey;

            PropagatorResult[] nestedValues = new PropagatorResult[record.FieldCount];
            for (int ordinal = 0; ordinal < nestedValues.Length; ordinal++)
            {
                nestedValues[ordinal] = metadata.RetrieveMember(stateEntry, record, useCurrentValues, key,
                    ordinal, modifiedPropertiesBehavior);
            }

            return PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified);
        }
 private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName)
 {
     int columnOrdinal;
     try
     {
         columnOrdinal = reader.GetOrdinal(columnName);
     }
     catch (IndexOutOfRangeException)
     {
         throw new UpdateException(
             Strings.Update_MissingResultColumn(columnName), null, GetStateEntries(translator).Cast<ObjectStateEntry>().Distinct());
     }
     return columnOrdinal;
 }
            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>
 /// 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 ExtractorMetadata(EntitySetBase entitySetBase, StructuralType type, UpdateTranslator translator)
        {
            EntityUtil.CheckArgumentNull(entitySetBase, "entitySetBase");
            m_type = EntityUtil.CheckArgumentNull(type, "type");
            m_translator = EntityUtil.CheckArgumentNull(translator, "translator");

            EntityType entityType = null;
            Set<EdmMember> keyMembers;
            Set<EdmMember> foreignKeyMembers;

            switch (type.BuiltInTypeKind)
            {
                case BuiltInTypeKind.RowType:
                    // for row types (which are actually association end key records in disguise), all members
                    // are keys
                    keyMembers = new Set<EdmMember>(((RowType)type).Properties).MakeReadOnly();
                    foreignKeyMembers = Set<EdmMember>.Empty;
                    break;
                case BuiltInTypeKind.EntityType:
                    entityType = (EntityType)type;
                    keyMembers = new Set<EdmMember>(entityType.KeyMembers).MakeReadOnly();
                    foreignKeyMembers = new Set<EdmMember>(((EntitySet)entitySetBase).ForeignKeyDependents
                        .SelectMany(fk => fk.Item2.ToProperties)).MakeReadOnly();
                    break;
                default:
                    keyMembers = Set<EdmMember>.Empty;
                    foreignKeyMembers = Set<EdmMember>.Empty;
                    break;
            }

            IBaseList<EdmMember> members = TypeHelpers.GetAllStructuralMembers(type);
            m_memberMap = new MemberInformation[members.Count];
            // for each member, cache expensive to compute metadata information
            for (int ordinal = 0; ordinal < members.Count; ordinal++)
            {
                EdmMember member = members[ordinal];
                // figure out flags for this member
                PropagatorFlags flags = PropagatorFlags.NoFlags;
                int? entityKeyOrdinal = default(int?);
                
                if (keyMembers.Contains(member))
                {
                    flags |= PropagatorFlags.Key;
                    if (null != entityType)
                    {
                        entityKeyOrdinal = entityType.KeyMembers.IndexOf(member);
                    }
                }
                if (foreignKeyMembers.Contains(member))
                {
                    flags |= PropagatorFlags.ForeignKey;
                }


                if (MetadataHelper.GetConcurrencyMode(member) == ConcurrencyMode.Fixed)
                {
                    flags |= PropagatorFlags.ConcurrencyValue;
                }

                // figure out whether this member is mapped to any server generated
                // columns in the store
                bool isServerGenerated = m_translator.ViewLoader.IsServerGen(entitySetBase, m_translator.MetadataWorkspace, member);

                // figure out whether member nullability is used as a condition in mapping
                bool isNullConditionMember = m_translator.ViewLoader.IsNullConditionMember(entitySetBase, m_translator.MetadataWorkspace, member);

                // add information about this member
                m_memberMap[ordinal] = new MemberInformation(ordinal, entityKeyOrdinal, flags, member, isServerGenerated, isNullConditionMember);
            }
        }
 /// <summary>
 /// Constructs a new placeholder creator.
 /// </summary>
 /// <param name="parent">Context used to generate all elements of the placeholder.</param>
 private ExtentPlaceholderCreator(UpdateTranslator parent)
 {
     EntityUtil.CheckArgumentNull(parent, "parent");
     m_parent = parent;
 }
            // 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);
            }