internal ExtractedStateEntry(EntityState state, PropagatorResult original, PropagatorResult current, IEntityStateEntry source)
 {
     State = state;
     Original = original;
     Current = current;
     Source = source;
 }
        /// <summary>
        ///     Builds an update command.
        /// </summary>
        /// <param name="oldRow"> Old value of the row being updated. </param>
        /// <param name="newRow"> New value for the row being updated. </param>
        /// <param name="processor"> Context for the table containing row. </param>
        /// <returns> Update command. </returns>
        internal UpdateCommand BuildUpdateCommand(
            PropagatorResult oldRow,
            PropagatorResult newRow, TableChangeProcessor processor)
        {
            // If we're updating a row, the row may not need to be touched (e.g., no concurrency validation required)
            var rowMustBeTouched = false;

            var target = GetTarget(processor);

            // Create set clauses and returning parameter
            Dictionary<int, string> outputIdentifiers;
            DbExpression returning;
            var setClauses = new List<DbModificationClause>();
            foreach (var clause in BuildSetClauses(
                target, newRow, oldRow, processor, /* insertMode */ false, out outputIdentifiers, out returning,
                ref rowMustBeTouched))
            {
                setClauses.Add(clause);
            }

            // Construct predicate identifying the row to modify
            var predicate = BuildPredicate(target, oldRow, newRow, processor, ref rowMustBeTouched);

            if (0 == setClauses.Count)
            {
                if (rowMustBeTouched)
                {
                    var stateEntries = new List<IEntityStateEntry>();
                    stateEntries.AddRange(
                        SourceInterpreter.GetAllStateEntries(
                            oldRow, m_translator, processor.Table));
                    stateEntries.AddRange(
                        SourceInterpreter.GetAllStateEntries(
                            newRow, m_translator, processor.Table));
                    if (stateEntries.All(it => (it.State == EntityState.Unchanged)))
                    {
                        rowMustBeTouched = false;
                    }
                }

                // Determine if there is nothing to do (i.e., no values to set, 
                // no computed columns, and no concurrency validation required)
                if (!rowMustBeTouched)
                {
                    return null;
                }
            }

            // Initialize DML command tree
            var commandTree =
                new DbUpdateCommandTree(
                    m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate, setClauses.AsReadOnly(), returning);

            // Create command
            UpdateCommand command = new DynamicUpdateCommand(
                processor, m_translator, ModificationOperator.Update, oldRow, newRow, commandTree, outputIdentifiers);

            return command;
        }
        // <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)
        {
            DebugCheck.NotNull(source);
            DebugCheck.NotNull(translator);
            DebugCheck.NotNull(sourceTable);

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

            return new ReadOnlyCollection<IEntityStateEntry>(interpreter.m_stateEntries);
        }
                // <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>
                // <returns> Cloned placeholder with key values </returns>
                internal static PropagatorResult Populate(
                    PropagatorResult placeholder, CompositeKey key,
                    CompositeKey placeholderKey, PopulateMode mode)
                {
                    DebugCheck.NotNull(placeholder);
                    DebugCheck.NotNull(key);
                    DebugCheck.NotNull(placeholderKey);

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

                    var result = placeholder.Replace(
                        node =>
                            {
                                // See if this is a key element
                                var keyIndex = -1;
                                for (var 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
                                    var value = isNull ? null : node.GetSimpleValue();
                                    return PropagatorResult.CreateSimpleValue(flags, value);
                                }
                            });

                    return result;
                }
        private void RetrieveResultMarkup(PropagatorResult source)
        {
            DebugCheck.NotNull(source);

            if (source.Identifier
                != PropagatorResult.NullIdentifier)
            {
                // state entries travel with identifiers. several state entries may be merged
                // into a single identifier result via joins in the update mapping view
                do
                {
                    if (null != source.StateEntry)
                    {
                        m_stateEntries.Add(source.StateEntry);
                        if (source.Identifier
                            != PropagatorResult.NullIdentifier)
                        {
                            // if this is an identifier, it may also be registered with an "owner".
                            // Return the owner as well if the owner is also mapped to this table.
                            PropagatorResult owner;
                            if (m_translator.KeyManager.TryGetIdentifierOwner(source.Identifier, out owner)
                                && null != owner.StateEntry
                                && ExtentInScope(owner.StateEntry.EntitySet))
                            {
                                m_stateEntries.Add(owner.StateEntry);
                            }

                            // Check if are any referential constraints. If so, the entity key
                            // implies that the dependent relationship instance is also being
                            // handled in this result.
                            foreach (var stateEntry in m_translator.KeyManager.GetDependentStateEntries(source.Identifier))
                            {
                                m_stateEntries.Add(stateEntry);
                            }
                        }
                    }
                    source = source.Next;
                }
                while (null != source);
            }
            else if (!source.IsSimple
                     && !source.IsNull)
            {
                // walk children
                foreach (var child in source.GetMemberValues())
                {
                    RetrieveResultMarkup(child);
                }
            }
        }
        /// <summary>
        ///     Builds a delete command.
        /// </summary>
        /// <param name="oldRow"> Value of the row being deleted. </param>
        /// <param name="processor"> Context for the table containing row. </param>
        /// <returns> Delete command. </returns>
        internal UpdateCommand BuildDeleteCommand(PropagatorResult oldRow, TableChangeProcessor processor)
        {
            // If we're deleting a row, the row must always be touched
            var rowMustBeTouched = true;

            // Initialize DML command tree
            var target = GetTarget(processor);

            // Create delete predicate
            var predicate = BuildPredicate(target, oldRow, null, processor, ref rowMustBeTouched);
            var commandTree = new DbDeleteCommandTree(m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate);

            // Set command
            // Initialize delete command
            UpdateCommand command = new DynamicUpdateCommand(
                processor, m_translator, ModificationOperator.Delete, oldRow, null, commandTree, null);

            return command;
        }
示例#7
0
            // <summary>
            // Produce a tuple containing joined rows.
            // </summary>
            // <param name="left"> Left row. </param>
            // <param name="right"> Right row. </param>
            // <param name="result"> Result change node; used for type information. </param>
            // <returns> Result of joining the input rows. </returns>
            private PropagatorResult CreateResultTuple(
                Tuple <CompositeKey, PropagatorResult> left, Tuple <CompositeKey, PropagatorResult> right, ChangeNode result)
            {
                // using ref compare to avoid triggering value based
                var leftKey  = left.Item1;
                var rightKey = right.Item1;
                Dictionary <PropagatorResult, PropagatorResult> map = null;

                if (!ReferenceEquals(null, leftKey)
                    &&
                    !ReferenceEquals(null, rightKey)
                    &&
                    !ReferenceEquals(leftKey, rightKey))
                {
                    // Merge key values from the left and the right (since they're equal, there's a possibility we'll
                    // project values only from the left or the right hand side and lose important context.)
                    var mergedKey = leftKey.Merge(m_parent.m_updateTranslator.KeyManager, rightKey);
                    // create a dictionary so that we can replace key values with merged key values (carrying context
                    // from both sides)
                    map = new Dictionary <PropagatorResult, PropagatorResult>();
                    for (var i = 0; i < leftKey.KeyComponents.Length; i++)
                    {
                        map[leftKey.KeyComponents[i]]  = mergedKey.KeyComponents[i];
                        map[rightKey.KeyComponents[i]] = mergedKey.KeyComponents[i];
                    }
                }

                var joinRecordValues = new PropagatorResult[2];

                joinRecordValues[0] = left.Item2;
                joinRecordValues[1] = right.Item2;
                var join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false);

                // replace with merged key values as appropriate
                if (null != map)
                {
                    PropagatorResult replacement;
                    join = join.Replace(original => map.TryGetValue(original, out replacement) ? replacement : original);
                }

                return(join);
            }
        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 DynamicUpdateCommand(
            TableChangeProcessor processor, UpdateTranslator translator,
            ModificationOperator modificationOperator, PropagatorResult originalValues, PropagatorResult currentValues,
            DbModificationCommandTree tree, Dictionary <int, string> outputIdentifiers)
            : base(translator, originalValues, currentValues)
        {
            DebugCheck.NotNull(processor);
            DebugCheck.NotNull(translator);
            DebugCheck.NotNull(tree);

            _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));
                        }
                    }
                }
            }
        }
 private void AddReferencedEntities(
     UpdateTranslator translator,
     PropagatorResult result,
     KeyToListMap <EntityKey, UpdateCommand> referencedEntities)
 {
     foreach (PropagatorResult memberValue in result.GetMemberValues())
     {
         if (memberValue.IsSimple && memberValue.Identifier != -1 && PropagatorFlags.ForeignKey == (memberValue.PropagatorFlags & PropagatorFlags.ForeignKey))
         {
             foreach (int directReference in translator.KeyManager.GetDirectReferences(memberValue.Identifier))
             {
                 PropagatorResult owner;
                 if (translator.KeyManager.TryGetIdentifierOwner(directReference, out owner) && owner.StateEntry != null)
                 {
                     referencedEntities.Add(owner.StateEntry.EntityKey, this);
                 }
             }
         }
     }
 }
示例#11
0
        private Dictionary <CompositeKey, PropagatorResult> ProcessKeys(
            UpdateCompiler compiler,
            List <PropagatorResult> changes,
            Set <CompositeKey> keys)
        {
            Dictionary <CompositeKey, PropagatorResult> dictionary = new Dictionary <CompositeKey, PropagatorResult>(compiler.m_translator.KeyComparer);

            foreach (PropagatorResult change in changes)
            {
                PropagatorResult row          = change;
                CompositeKey     compositeKey = new CompositeKey(this.GetKeyConstants(row));
                PropagatorResult other;
                if (dictionary.TryGetValue(compositeKey, out other))
                {
                    this.DiagnoseKeyCollision(compiler, change, compositeKey, other);
                }
                dictionary.Add(compositeKey, row);
                keys.Add(compositeKey);
            }
            return(dictionary);
        }
示例#12
0
            protected PropagatorResult[] ReplaceValues(
                Func <PropagatorResult, PropagatorResult> map)
            {
                PropagatorResult[] propagatorResultArray = new PropagatorResult[this.m_values.Length];
                bool flag = false;

                for (int index = 0; index < propagatorResultArray.Length; ++index)
                {
                    PropagatorResult propagatorResult = this.m_values[index].Replace(map);
                    if (!object.ReferenceEquals((object)propagatorResult, (object)this.m_values[index]))
                    {
                        flag = true;
                    }
                    propagatorResultArray[index] = propagatorResult;
                }
                if (!flag)
                {
                    return((PropagatorResult[])null);
                }
                return(propagatorResultArray);
            }
示例#13
0
            public void Wraps_exceptions()
            {
                var updateTranslatorMock = new Mock <UpdateTranslator>
                {
                    CallBase = true
                };

                var dbException = new Mock <DbException>("Exception message").Object;

                var updateCommandMock = new Mock <UpdateCommand>(
                    updateTranslatorMock.Object,
                    PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0),
                    PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0));

                updateCommandMock.Setup(
                    m => m.Execute(
                        It.IsAny <Dictionary <int, object> >(),
                        It.IsAny <List <KeyValuePair <PropagatorResult, object> > >(),
                        It.IsAny <IDbCommandInterceptor>()))
                .Returns(() => { throw dbException; });

                var objectStateManager = new Mock <ObjectStateManager>
                {
                    CallBase = true
                }.Object;
                var objectStateEntryMock = new Mock <ObjectStateEntry>(objectStateManager, /*entitySet:*/ null, EntityState.Unchanged);

                updateCommandMock.Setup(m => m.GetStateEntries(It.IsAny <UpdateTranslator>()))
                .Returns(new[] { objectStateEntryMock.Object });

                new List <KeyValuePair <PropagatorResult, object> >();
                updateTranslatorMock.Protected().Setup <IEnumerable <UpdateCommand> >("ProduceCommands").Returns(
                    new[] { updateCommandMock.Object });

                var exception = Assert.Throws <UpdateException>(() => updateTranslatorMock.Object.Update());

                Assert.Equal(Strings.Update_GeneralExecutionException, exception.Message);
                Assert.Same(dbException, exception.InnerException);
                Assert.Same(objectStateEntryMock.Object, exception.StateEntries.Single());
            }
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            DebugCheck.NotNull(translator);
            DebugCheck.NotNull(stateEntry);

            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:
                    Debug.Assert(false, "Unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                    Original = null;
                    Current = null;
                    break;
            }
        }
            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry)
            {
                ModificationFunctionMapping functionMapping = this.GetFunctionMapping(stateEntry).Item2;
                EntityKey entityKey = stateEntry.Source.EntityKey;
                HashSet <IEntityStateEntry> entityStateEntrySet = new HashSet <IEntityStateEntry>()
                {
                    stateEntry.Source
                };
                IEnumerable <Tuple <AssociationEndMember, IEntityStateEntry> > tuples      = functionMapping.CollocatedAssociationSetEnds.Join <AssociationSetEnd, IEntityStateEntry, StructuralType, Tuple <AssociationEndMember, IEntityStateEntry> >(translator.GetRelationships(entityKey), (Func <AssociationSetEnd, StructuralType>)(end => end.CorrespondingAssociationEndMember.DeclaringType), (Func <IEntityStateEntry, StructuralType>)(candidateEntry => (StructuralType)candidateEntry.EntitySet.ElementType), (Func <AssociationSetEnd, IEntityStateEntry, Tuple <AssociationEndMember, IEntityStateEntry> >)((end, candidateEntry) => Tuple.Create <AssociationEndMember, IEntityStateEntry>(end.CorrespondingAssociationEndMember, candidateEntry)));
                Dictionary <AssociationEndMember, IEntityStateEntry>           dictionary1 = new Dictionary <AssociationEndMember, IEntityStateEntry>();
                Dictionary <AssociationEndMember, IEntityStateEntry>           dictionary2 = new Dictionary <AssociationEndMember, IEntityStateEntry>();

                foreach (Tuple <AssociationEndMember, IEntityStateEntry> tuple in tuples)
                {
                    ModificationFunctionMappingTranslator.EntitySetTranslator.ProcessReferenceCandidate(entityKey, entityStateEntrySet, dictionary1, dictionary2, tuple.Item1, tuple.Item2);
                }
                FunctionUpdateCommand command;

                if (entityStateEntrySet.All <IEntityStateEntry>((Func <IEntityStateEntry, bool>)(e => e.State == EntityState.Unchanged)))
                {
                    command = (FunctionUpdateCommand)null;
                }
                else
                {
                    command = new FunctionUpdateCommand(functionMapping, translator, new ReadOnlyCollection <IEntityStateEntry>((IList <IEntityStateEntry>)entityStateEntrySet.ToList <IEntityStateEntry>()), stateEntry);
                    ModificationFunctionMappingTranslator.EntitySetTranslator.BindFunctionParameters(translator, stateEntry, functionMapping, command, dictionary1, dictionary2);
                    if (functionMapping.ResultBindings != null)
                    {
                        foreach (ModificationFunctionResultBinding resultBinding in functionMapping.ResultBindings)
                        {
                            PropagatorResult memberValue = stateEntry.Current.GetMemberValue((EdmMember)resultBinding.Property);
                            command.AddResultColumn(translator, resultBinding.ColumnName, memberValue);
                        }
                    }
                }
                return(command);
            }
示例#16
0
        internal void AddResultColumn(
            UpdateTranslator translator,
            string columnName,
            PropagatorResult result)
        {
            if (this.ResultColumns == null)
            {
                this.ResultColumns = new List <KeyValuePair <string, PropagatorResult> >(2);
            }
            this.ResultColumns.Add(new KeyValuePair <string, PropagatorResult>(columnName, result));
            int identifier = result.Identifier;

            if (-1 == identifier)
            {
                return;
            }
            if (translator.KeyManager.HasPrincipals(identifier))
            {
                throw new InvalidOperationException(Strings.Update_GeneratedDependent((object)columnName));
            }
            this.AddOutputIdentifier(columnName, identifier);
        }
        private void ValidateReferentialIntegrityGraphAcyclic(
            int node,
            byte[] color,
            KeyManager.LinkedList <int> parent)
        {
            color[node] = (byte)2;
            KeyManager.LinkedList <int> .Add(ref parent, node);

            foreach (int node1 in KeyManager.LinkedList <int> .Enumerate(this._identifiers[node].References))
            {
                switch (color[node1])
                {
                case 0:
                    this.ValidateReferentialIntegrityGraphAcyclic(node1, color, parent);
                    continue;

                case 2:
                    List <IEntityStateEntry> source = new List <IEntityStateEntry>();
                    foreach (int index in KeyManager.LinkedList <int> .Enumerate(parent))
                    {
                        PropagatorResult owner = this._identifiers[index].Owner;
                        if (owner != null)
                        {
                            source.Add(owner.StateEntry);
                        }
                        if (index == node1)
                        {
                            break;
                        }
                    }
                    throw new UpdateException(Strings.Update_CircularRelationships, (Exception)null, source.Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>());

                default:
                    continue;
                }
            }
            color[node] = (byte)1;
        }
示例#18
0
        internal UpdateCommand BuildUpdateCommand(
            PropagatorResult oldRow,
            PropagatorResult newRow,
            TableChangeProcessor processor)
        {
            bool rowMustBeTouched = false;
            DbExpressionBinding         target = UpdateCompiler.GetTarget(processor);
            List <DbModificationClause> modificationClauseList = new List <DbModificationClause>();
            Dictionary <int, string>    outputIdentifiers;
            DbExpression returning;

            foreach (DbModificationClause buildSetClause in this.BuildSetClauses(target, newRow, oldRow, processor, false, out outputIdentifiers, out returning, ref rowMustBeTouched))
            {
                modificationClauseList.Add(buildSetClause);
            }
            DbExpression predicate = this.BuildPredicate(target, oldRow, newRow, processor, ref rowMustBeTouched);

            if (modificationClauseList.Count == 0)
            {
                if (rowMustBeTouched)
                {
                    List <IEntityStateEntry> source = new List <IEntityStateEntry>();
                    source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(oldRow, this.m_translator, processor.Table));
                    source.AddRange((IEnumerable <IEntityStateEntry>)SourceInterpreter.GetAllStateEntries(newRow, this.m_translator, processor.Table));
                    if (source.All <IEntityStateEntry>((Func <IEntityStateEntry, bool>)(it => it.State == EntityState.Unchanged)))
                    {
                        rowMustBeTouched = false;
                    }
                }
                if (!rowMustBeTouched)
                {
                    return((UpdateCommand)null);
                }
            }
            DbUpdateCommandTree updateCommandTree = new DbUpdateCommandTree(this.m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate, new ReadOnlyCollection <DbModificationClause>((IList <DbModificationClause>)modificationClauseList), returning);

            return((UpdateCommand) new DynamicUpdateCommand(processor, this.m_translator, ModificationOperator.Update, oldRow, newRow, (DbModificationCommandTree)updateCommandTree, outputIdentifiers));
        }
示例#19
0
 internal override PropagatorResult Merge(
     KeyManager keyManager,
     PropagatorResult other)
 {
     PropagatorResult.KeyValue next = other as PropagatorResult.KeyValue;
     if (next == null)
     {
         EntityUtil.InternalError(EntityUtil.InternalErrorCode.UpdatePipelineResultRequestInvalid, 0, (object)"KeyValue.Merge");
     }
     if (this.Identifier != next.Identifier)
     {
         if (keyManager.GetPrincipals(next.Identifier).Contains <int>(this.Identifier))
         {
             return((PropagatorResult)this.ReplicateResultWithNewNext(next));
         }
         return((PropagatorResult)next.ReplicateResultWithNewNext(this));
     }
     if (this.m_stateEntry == null || this.m_stateEntry.IsRelationship)
     {
         return((PropagatorResult)next.ReplicateResultWithNewNext(this));
     }
     return((PropagatorResult)this.ReplicateResultWithNewNext(next));
 }
            internal override PropagatorResult Merge(KeyManager keyManager, PropagatorResult other)
            {
                var otherKey = other as KeyValue;

                if (null == otherKey)
                {
                    EntityUtil.InternalError(EntityUtil.InternalErrorCode.UpdatePipelineResultRequestInvalid, 0, "KeyValue.Merge");
                }

                // Determine which key (this or otherKey) is first in the chain. Principal keys take
                // precedence over dependent keys and entities take precedence over relationships.
                if (Identifier != otherKey.Identifier)
                {
                    // Find principal (if any)
                    if (keyManager.GetPrincipals(otherKey.Identifier).Contains(Identifier))
                    {
                        return(ReplicateResultWithNewNext(otherKey));
                    }
                    else
                    {
                        return(otherKey.ReplicateResultWithNewNext(this));
                    }
                }
                else
                {
                    // Entity takes precedence of relationship
                    if (null == m_stateEntry ||
                        m_stateEntry.IsRelationship)
                    {
                        return(otherKey.ReplicateResultWithNewNext(this));
                    }
                    else
                    {
                        return(ReplicateResultWithNewNext(otherKey));
                    }
                }
            }
            public void Execute_calls_interceptor_when_there_is_no_reader_and_cancels_execution()
            {
                var mockUpdateTranslator = new Mock <UpdateTranslator>(MockBehavior.Strict);

                mockUpdateTranslator.Setup(m => m.CommandTimeout).Returns(43);
                var entityConnection = new Mock <EntityConnection>().Object;

                mockUpdateTranslator.Setup(m => m.Connection).Returns(entityConnection);

                var mockDbModificationCommandTree = new Mock <DbModificationCommandTree>();
                var mockDynamicUpdateCommand      = new Mock <DynamicUpdateCommand>(
                    new Mock <TableChangeProcessor>().Object, mockUpdateTranslator.Object,
                    ModificationOperator.Delete, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0),
                    PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0), mockDbModificationCommandTree.Object,
                    /*outputIdentifiers*/ null)
                {
                    CallBase = true
                };

                var mockDbCommand = new Mock <DbCommand>();

                var identifierValues = new Dictionary <int, object>();

                mockDynamicUpdateCommand.Protected().Setup <DbCommand>("CreateCommand", identifierValues).Returns(mockDbCommand.Object);

                var generatedValues = new List <KeyValuePair <PropagatorResult, object> >();

                var mockCommandInterceptor = new Mock <IDbCommandInterceptor>();

                var rowsAffectedResult = mockDynamicUpdateCommand.Object.Execute(
                    identifierValues, generatedValues, mockCommandInterceptor.Object);

                Assert.Equal(1, rowsAffectedResult);

                mockCommandInterceptor.Verify(i => i.Intercept(mockDbCommand.Object));
                mockDbCommand.Verify(m => m.ExecuteNonQuery(), Times.Never());
            }
 private void RetrieveResultMarkup(PropagatorResult source)
 {
     if (source.Identifier != -1)
     {
         do
         {
             if (source.StateEntry != null)
             {
                 this.m_stateEntries.Add(source.StateEntry);
                 if (source.Identifier != -1)
                 {
                     PropagatorResult owner;
                     if (this.m_translator.KeyManager.TryGetIdentifierOwner(source.Identifier, out owner) && owner.StateEntry != null && this.ExtentInScope(owner.StateEntry.EntitySet))
                     {
                         this.m_stateEntries.Add(owner.StateEntry);
                     }
                     foreach (IEntityStateEntry dependentStateEntry in this.m_translator.KeyManager.GetDependentStateEntries(source.Identifier))
                     {
                         this.m_stateEntries.Add(dependentStateEntry);
                     }
                 }
             }
             source = source.Next;
         }while (source != null);
     }
     else
     {
         if (source.IsSimple || source.IsNull)
         {
             return;
         }
         foreach (PropagatorResult memberValue in source.GetMemberValues())
         {
             this.RetrieveResultMarkup(memberValue);
         }
     }
 }
示例#23
0
            // <summary>
            // Constructor
            // </summary>
            // <param name="metadata"> Sets Metadata </param>
            // <param name="record"> Record containing key value </param>
            // <param name="isTarget"> Indicates whether the source or target end of the constraint is being pulled </param>
            // <param name="isInsert"> Indicates whether this is an insert dependency or a delete dependency </param>
            private ForeignKeyValue(
                ReferentialConstraint metadata, PropagatorResult record,
                bool isTarget, bool isInsert)
            {
                Metadata = metadata;

                // construct key
                IList <EdmProperty> keyProperties = isTarget
                                                       ? metadata.FromProperties
                                                       : metadata.ToProperties;
                var keyValues     = new PropagatorResult[keyProperties.Count];
                var hasNullMember = false;

                for (var i = 0; i < keyValues.Length; i++)
                {
                    keyValues[i] = record.GetMemberValue(keyProperties[i]);
                    if (keyValues[i].IsNull)
                    {
                        hasNullMember = true;
                        break;
                    }
                }

                if (hasNullMember)
                {
                    // set key to null to indicate that it is not behaving as a key
                    // (in SQL, keys with null parts do not participate in constraints)
                    Key = null;
                }
                else
                {
                    Key = new CompositeKey(keyValues);
                }

                IsInsert = isInsert;
            }
            private ForeignKeyValue(
                ReferentialConstraint metadata,
                PropagatorResult record,
                bool isTarget,
                bool isInsert)
            {
                this.Metadata = metadata;
                IList <EdmProperty> edmPropertyList = isTarget ? (IList <EdmProperty>)metadata.FromProperties : (IList <EdmProperty>)metadata.ToProperties;

                PropagatorResult[] constants = new PropagatorResult[edmPropertyList.Count];
                bool flag = false;

                for (int index = 0; index < constants.Length; ++index)
                {
                    constants[index] = record.GetMemberValue((EdmMember)edmPropertyList[index]);
                    if (constants[index].IsNull)
                    {
                        flag = true;
                        break;
                    }
                }
                this.Key      = !flag ? new CompositeKey(constants) : (CompositeKey)null;
                this.IsInsert = isInsert;
            }
示例#25
0
 private void AddReferencedEntities(
     UpdateTranslator translator, PropagatorResult result, KeyToListMap <EntityKey, UpdateCommand> referencedEntities)
 {
     foreach (var property in result.GetMemberValues())
     {
         if (property.IsSimple &&
             property.Identifier != PropagatorResult.NullIdentifier
             &&
             (PropagatorFlags.ForeignKey == (property.PropagatorFlags & PropagatorFlags.ForeignKey)))
         {
             foreach (var principal in translator.KeyManager.GetDirectReferences(property.Identifier))
             {
                 PropagatorResult owner;
                 if (translator.KeyManager.TryGetIdentifierOwner(principal, out owner)
                     &&
                     null != owner.StateEntry)
                 {
                     Debug.Assert(!owner.StateEntry.IsRelationship, "owner must not be a relationship");
                     referencedEntities.Add(owner.StateEntry.EntityKey, this);
                 }
             }
         }
     }
 }
示例#26
0
        /// <summary>
        ///     Determines column/value used to set values for a row.
        /// </summary>
        /// <remarks>
        ///     The following columns are not included in the result:
        ///     <list>
        ///         <item>Keys in non-insert operations (keys are only set for inserts).</item>
        ///         <item>Values flagged 'preserve' (these are values the propagator claims are untouched).</item>
        ///         <item>Server generated values.</item>
        ///     </list>
        /// </remarks>
        /// <param name="target"> Expression binding representing the table. </param>
        /// <param name="row"> Row containing values to set. </param>
        /// <param name="processor"> Context for table. </param>
        /// <param name="insertMode"> Determines whether key columns and 'preserve' columns are omitted from the list. </param>
        /// <param name="outputIdentifiers"> Dictionary listing server generated identifiers. </param>
        /// <param name="returning"> DbExpression describing result projection for server generated values. </param>
        /// <param name="rowMustBeTouched"> Indicates whether the row must be touched because it produces a value (e.g. computed) </param>
        /// <returns> Column value pairs. </returns>
        private IEnumerable <DbModificationClause> BuildSetClauses(
            DbExpressionBinding target, PropagatorResult row,
            PropagatorResult originalRow, TableChangeProcessor processor, bool insertMode, out Dictionary <int, string> outputIdentifiers,
            out DbExpression returning,
            ref bool rowMustBeTouched)
        {
            var setClauses         = new Dictionary <EdmProperty, PropagatorResult>();
            var returningArguments = new List <KeyValuePair <string, DbExpression> >();

            outputIdentifiers = new Dictionary <int, string>();

            // Determine which flags indicate a property should be omitted from the set list.
            var omitMask = insertMode
                               ? PropagatorFlags.NoFlags
                               : PropagatorFlags.Preserve | PropagatorFlags.Unknown;

            for (var propertyOrdinal = 0; propertyOrdinal < processor.Table.ElementType.Properties.Count; propertyOrdinal++)
            {
                var property = processor.Table.ElementType.Properties[propertyOrdinal];

                // Type members and result values are ordinally aligned
                var propertyResult = row.GetMemberValue(propertyOrdinal);

                if (PropagatorResult.NullIdentifier
                    != propertyResult.Identifier)
                {
                    // retrieve principal value
                    propertyResult = propertyResult.ReplicateResultWithNewValue(
                        m_translator.KeyManager.GetPrincipalValue(propertyResult));
                }

                var omitFromSetList = false;

                Debug.Assert(propertyResult.IsSimple);

                // Determine if this is a key value
                var isKey = false;
                for (var i = 0; i < processor.KeyOrdinals.Length; i++)
                {
                    if (processor.KeyOrdinals[i] == propertyOrdinal)
                    {
                        isKey = true;
                        break;
                    }
                }

                // check if this value should be omitted
                var flags = PropagatorFlags.NoFlags;
                if (!insertMode && isKey)
                {
                    // Keys are only set for inserts
                    omitFromSetList = true;
                }
                else
                {
                    // See if this value has been marked up with some context. If so, add the flag information
                    // from the markup. Markup includes information about whether the property is a concurrency value,
                    // whether it is known (it may be a property that is preserved across an update for instance)
                    flags |= propertyResult.PropagatorFlags;
                }

                // Determine if this value is server-generated
                var genPattern  = MetadataHelper.GetStoreGeneratedPattern(property);
                var isServerGen = genPattern == StoreGeneratedPattern.Computed ||
                                  (insertMode && genPattern == StoreGeneratedPattern.Identity);
                if (isServerGen)
                {
                    var propertyExpression = target.Variable.Property(property);
                    returningArguments.Add(new KeyValuePair <string, DbExpression>(property.Name, propertyExpression));

                    // check if this is a server generated identifier
                    var identifier = propertyResult.Identifier;
                    if (PropagatorResult.NullIdentifier != identifier)
                    {
                        if (m_translator.KeyManager.HasPrincipals(identifier))
                        {
                            throw new InvalidOperationException(Strings.Update_GeneratedDependent(property.Name));
                        }
                        outputIdentifiers.Add(identifier, property.Name);

                        // If this property maps an identifier (in the update pipeline) it may
                        // also be a store key. If so, the pattern had better be "Identity"
                        // since otherwise we're dealing with a mutable key.
                        if (genPattern != StoreGeneratedPattern.Identity
                            &&
                            processor.IsKeyProperty(propertyOrdinal))
                        {
                            throw new NotSupportedException(
                                      Strings.Update_NotSupportedComputedKeyColumn(
                                          EdmProviderManifest.StoreGeneratedPatternFacetName,
                                          XmlConstants.Computed,
                                          XmlConstants.Identity,
                                          property.Name,
                                          property.DeclaringType.FullName));
                        }
                    }
                }

                if (PropagatorFlags.NoFlags
                    != (flags & (omitMask)))
                {
                    // column value matches "omit" pattern, therefore should not be set
                    omitFromSetList = true;
                }
                else if (isServerGen)
                {
                    // column value does not match "omit" pattern, but it is server generated
                    // so it cannot be set
                    omitFromSetList = true;

                    // if the row has a modified value overridden by server gen,
                    // it must still be touched in order to retrieve the value
                    rowMustBeTouched = true;
                }

                // make the user is not updating an identity value
                if (!omitFromSetList &&
                    !insertMode &&
                    genPattern == StoreGeneratedPattern.Identity)
                {
                    //throw the error only if the value actually changed
                    Debug.Assert(originalRow != null, "Updated records should have a original row");
                    var originalPropertyResult = originalRow.GetMemberValue(propertyOrdinal);
                    Debug.Assert(originalPropertyResult.IsSimple, "Server Gen property that is not primitive?");
                    Debug.Assert(propertyResult.IsSimple, "Server Gen property that is not primitive?");

                    if (!ByValueEqualityComparer.Default.Equals(originalPropertyResult.GetSimpleValue(), propertyResult.GetSimpleValue()))
                    {
                        throw new InvalidOperationException(
                                  Strings.Update_ModifyingIdentityColumn(
                                      XmlConstants.Identity,
                                      property.Name,
                                      property.DeclaringType.FullName));
                    }
                    else
                    {
                        omitFromSetList = true;
                    }
                }

                if (!omitFromSetList)
                {
                    setClauses.Add(property, propertyResult);
                }
            }

            // Construct returning projection
            if (0 < returningArguments.Count)
            {
                returning = DbExpressionBuilder.NewRow(returningArguments);
            }
            else
            {
                returning = null;
            }

            // Construct clauses corresponding to the set clauses
            var result = new List <DbModificationClause>(setClauses.Count);

            foreach (var setClause in setClauses)
            {
                var property = setClause.Key;

                result.Add(
                    new DbSetClause(
                        GeneratePropertyExpression(target, setClause.Key),
                        GenerateValueExpression(setClause.Key, setClause.Value)));
            }

            return(result);
        }
            // extracts key values from row expression
            private static CompositeKey ExtractKey(
                PropagatorResult change, ReadOnlyCollection<DbExpression> keySelectors)
            {
                DebugCheck.NotNull(change);
                DebugCheck.NotNull(keySelectors);

                var keyValues = new PropagatorResult[keySelectors.Count];
                for (var i = 0; i < keySelectors.Count; i++)
                {
                    var constant = Evaluator.Evaluate(keySelectors[i], change);
                    keyValues[i] = constant;
                }
                return new CompositeKey(keyValues);
            }
            // Find "sanctioned" default value
            internal static void GetPropagatorResultForPrimitiveType(PrimitiveType primitiveType, out PropagatorResult result)
            {
                object value;

                if (!TryGetDefaultValue(primitiveType, out value))
                {
                    // If none exists, default to lowest common denominator for constants
                    value = default(byte);
                }

                // Return a new constant expression flagged as unknown since the value is only there for
                // show. (Not entirely for show, because null constraints may require a value for a record,
                // whether that record is a placeholder or not).
                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value);
            }
        // Effects: given a propagator result, produces a constant expression describing that value.
        // Requires: all arguments are set, and the value must be simple (scalar)
        private DbExpression GenerateValueExpression(EdmProperty property, PropagatorResult value)
        {
            DebugCheck.NotNull(property);
            DebugCheck.NotNull(value);

            Debug.Assert(value.IsSimple);
            Debug.Assert(Helper.IsPrimitiveType(property.TypeUsage.EdmType), "Properties in SSpace should be primitive.");

            if (value.IsNull)
            {
                return Helper.GetModelTypeUsage(property).Null();
            }
            var principalValue = m_translator.KeyManager.GetPrincipalValue(value);

            if (Convert.IsDBNull(principalValue))
            {
                // although the result may be marked non-null (because it is an identifier) it is possible
                // there is no corresponding real value for the property yet
                return Helper.GetModelTypeUsage(property).Null();
            }
            else
            {
                // At this point we have already done any needed type checking and we potentially translated the type 
                // of the property to the SSpace (the property parameter is a property in the SSpace). However the value 
                // is here is a CSpace value. As a result it does not have to match the type of the property in SSpace.
                // Two cases here are:
                // - the type in CSpace does not exactly match the type in the SSpace (but is promotable)
                // - the type in CSpace is enum type and in this case it never matches the type in SSpace where enum type  
                //   does not exist
                // Since the types have already been checked it is safe just to convert the value from CSpace to the type
                // from SSpace.

                Debug.Assert(Nullable.GetUnderlyingType(principalValue.GetType()) == null, "Unexpected nullable type.");

                var propertyType = Helper.GetModelTypeUsage(property);
                var principalType = principalValue.GetType();

                if (principalType.IsEnum)
                {
                    principalValue = Convert.ChangeType(principalValue, principalType.GetEnumUnderlyingType(), CultureInfo.InvariantCulture);
                }

                var columnClrEquivalentType = ((PrimitiveType)propertyType.EdmType).ClrEquivalentType;

                if (principalType != columnClrEquivalentType)
                {
                    principalValue = Convert.ChangeType(principalValue, columnClrEquivalentType, CultureInfo.InvariantCulture);
                }

                return propertyType.Constant(principalValue);
            }
        }
        private void DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other)
        {
            var keyManager = compiler.m_translator.KeyManager;
            var otherKey = new CompositeKey(GetKeyConstants(other));

            // determine if the conflict is due to shared principal key values
            var sharedPrincipal = true;
            for (var i = 0; sharedPrincipal && i < key.KeyComponents.Length; i++)
            {
                var identifier1 = key.KeyComponents[i].Identifier;
                var identifier2 = otherKey.KeyComponents[i].Identifier;

                if (!keyManager.GetPrincipals(identifier1).Intersect(keyManager.GetPrincipals(identifier2)).Any())
                {
                    sharedPrincipal = false;
                }
            }

            if (sharedPrincipal)
            {
                // if the duplication is due to shared principals, there is a duplicate key exception
                var stateEntries = SourceInterpreter.GetAllStateEntries(change, compiler.m_translator, m_table)
                                                    .Concat(SourceInterpreter.GetAllStateEntries(other, compiler.m_translator, m_table));
                throw new UpdateException(Strings.Update_DuplicateKeys, null, stateEntries.Cast<ObjectStateEntry>().Distinct());
            }
            else
            {
                // if there are no shared principals, it implies that common dependents are the problem
                HashSet<IEntityStateEntry> commonDependents = null;
                foreach (var keyValue in key.KeyComponents.Concat(otherKey.KeyComponents))
                {
                    var dependents = new HashSet<IEntityStateEntry>();
                    foreach (var dependentId in keyManager.GetDependents(keyValue.Identifier))
                    {
                        PropagatorResult dependentResult;
                        if (keyManager.TryGetIdentifierOwner(dependentId, out dependentResult)
                            &&
                            null != dependentResult.StateEntry)
                        {
                            dependents.Add(dependentResult.StateEntry);
                        }
                    }
                    if (null == commonDependents)
                    {
                        commonDependents = new HashSet<IEntityStateEntry>(dependents);
                    }
                    else
                    {
                        commonDependents.IntersectWith(dependents);
                    }
                }

                // to ensure the exception shape is consistent with constraint violations discovered while processing
                // commands (a more conventional scenario in which different tables are contributing principal values)
                // wrap a DataConstraintException in an UpdateException
                throw new UpdateException(
                    Strings.Update_GeneralExecutionException,
                    new ConstraintException(Strings.Update_ReferentialConstraintIntegrityViolation),
                    commonDependents.Cast<ObjectStateEntry>().Distinct());
            }
        }
            /// <summary>
            ///     Given default values for children members, produces a new default expression for the requested (parent) member.
            /// </summary>
            /// <param name="node"> Parent member </param>
            /// <returns> Default value for parent member </returns>
            internal PropagatorResult Visit(EdmMember node)
            {
                PropagatorResult result;
                var nodeType = Helper.GetModelTypeUsage(node);

                if (Helper.IsScalarType(nodeType.EdmType))
                {
                    GetPropagatorResultForPrimitiveType(Helper.AsPrimitive(nodeType.EdmType), out result);
                }
                else
                {
                    // Construct a new 'complex type' (really any structural type) member.
                    var structuralType = (StructuralType)nodeType.EdmType;
                    var members = TypeHelpers.GetAllStructuralMembers(structuralType);

                    var args = new PropagatorResult[members.Count];
                    for (var ordinal = 0; ordinal < members.Count; ordinal++)
                        //                    foreach (EdmMember member in members)
                    {
                        args[ordinal] = Visit(members[ordinal]);
                    }

                    result = PropagatorResult.CreateStructuralValue(args, structuralType, false);
                }

                return result;
            }
 /// <summary>
 /// A result is merged with another when it is merged as part of an equi-join.
 /// </summary>
 /// <remarks>
 /// In theory, this should only ever be called on two keys (since we only join on
 /// keys). We throw in the base implementation, and override in KeyResult. By convention
 /// the principal key is always the first result in the chain (in case of an RIC). In
 /// addition, entity entries always appear before relationship entries.
 /// </remarks>
 /// <param name="other">Result to merge with.</param>
 /// <returns>Merged result.</returns>
 internal virtual PropagatorResult Merge(KeyManager keyManager, PropagatorResult other)
 {
     throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UpdatePipelineResultRequestInvalid, 0, "PropagatorResult.Merge");
 }
            internal override PropagatorResult Merge(KeyManager keyManager, PropagatorResult other)
            {
                var otherKey = other as KeyValue;
                if (null == otherKey)
                {
                    EntityUtil.InternalError(EntityUtil.InternalErrorCode.UpdatePipelineResultRequestInvalid, 0, "KeyValue.Merge");
                }

                // Determine which key (this or otherKey) is first in the chain. Principal keys take
                // precedence over dependent keys and entities take precedence over relationships.
                if (Identifier != otherKey.Identifier)
                {
                    // Find principal (if any)
                    if (keyManager.GetPrincipals(otherKey.Identifier).Contains(Identifier))
                    {
                        return ReplicateResultWithNewNext(otherKey);
                    }
                    else
                    {
                        return otherKey.ReplicateResultWithNewNext(this);
                    }
                }
                else
                {
                    // Entity takes precedence of relationship
                    if (null == m_stateEntry
                        || m_stateEntry.IsRelationship)
                    {
                        return otherKey.ReplicateResultWithNewNext(this);
                    }
                    else
                    {
                        return ReplicateResultWithNewNext(otherKey);
                    }
                }
            }
            public void Returns_rows_affected_when_there_is_a_reader()
            {
                var mockPrimitiveType = new Mock <PrimitiveType>();

                mockPrimitiveType.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.PrimitiveType);
                mockPrimitiveType.Setup(m => m.PrimitiveTypeKind).Returns(PrimitiveTypeKind.Int32);
                mockPrimitiveType.Setup(m => m.DataSpace).Returns(DataSpace.CSpace);
                var memberName  = "property";
                var edmProperty = new EdmProperty(memberName, TypeUsage.Create(mockPrimitiveType.Object));

                var entityType = new EntityType("", "", DataSpace.CSpace, Enumerable.Empty <string>(), new[] { edmProperty });

                entityType.SetReadOnly();

                var mockUpdateTranslator = new Mock <UpdateTranslator>(MockBehavior.Strict);

                mockUpdateTranslator.Setup(m => m.CommandTimeout).Returns(() => null);
                var entityConnection = new Mock <EntityConnection>().Object;

                mockUpdateTranslator.Setup(m => m.Connection).Returns(entityConnection);

                var mockDbModificationCommandTree = new Mock <DbModificationCommandTree>();

                mockDbModificationCommandTree.SetupGet(m => m.HasReader).Returns(true);

                var mockDynamicUpdateCommand = new Mock <DynamicUpdateCommand>(
                    new Mock <TableChangeProcessor>().Object, mockUpdateTranslator.Object,
                    ModificationOperator.Delete, PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0),
                    PropagatorResult.CreateStructuralValue(
                        new[] { PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0) },
                        entityType,
                        isModified: false),
                    mockDbModificationCommandTree.Object, /*outputIdentifiers*/ null)
                {
                    CallBase = true
                };

                var mockDbCommand = new Mock <DbCommand>();

                var dbValue          = 66;
                var mockDbDataReader = new Mock <DbDataReader>();

                mockDbDataReader.Setup(m => m.GetFieldValueAsync <object>(It.IsAny <int>(), It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult <object>(dbValue));
                var rowsToRead = 2;

                mockDbDataReader.Setup(m => m.ReadAsync(It.IsAny <CancellationToken>())).Returns(
                    () =>
                {
                    rowsToRead--;
                    return(Task.FromResult(rowsToRead > 0));
                });
                mockDbDataReader.Setup(m => m.FieldCount).Returns(1);
                mockDbDataReader.Setup(m => m.GetName(0)).Returns(memberName);
                mockDbDataReader.Setup(m => m.NextResultAsync(It.IsAny <CancellationToken>())).Returns(Task.FromResult(false));

                mockDbCommand.Protected()
                .Setup <Task <DbDataReader> >("ExecuteDbDataReaderAsync", CommandBehavior.SequentialAccess, It.IsAny <CancellationToken>())
                .Returns(Task.FromResult(mockDbDataReader.Object));

                var identifierValues = new Dictionary <int, object>();

                mockDynamicUpdateCommand.Protected().Setup <DbCommand>("CreateCommand", identifierValues).Returns(mockDbCommand.Object);

                var generatedValues = new List <KeyValuePair <PropagatorResult, object> >();

                var rowsAffectedResult =
                    mockDynamicUpdateCommand.Object.ExecuteAsync(identifierValues, generatedValues, CancellationToken.None).Result;

                Assert.Equal(1, rowsAffectedResult);
                Assert.Equal(1, generatedValues.Count);
                Assert.Equal(dbValue, generatedValues[0].Value);
                Assert.Equal(0, generatedValues[0].Key.GetSimpleValue());
            }
示例#35
0
        internal override async Task <long> ExecuteAsync(
            Dictionary <int, object> identifierValues,
            List <KeyValuePair <PropagatorResult, object> > generatedValues,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            long num;

            using (DbCommand command = this.CreateCommand(identifierValues))
            {
                EntityConnection connection = this.Translator.Connection;
                command.Transaction = connection.CurrentTransaction == null ? (DbTransaction)null : connection.CurrentTransaction.StoreTransaction;
                command.Connection  = connection.StoreConnection;
                if (this.Translator.CommandTimeout.HasValue)
                {
                    command.CommandTimeout = this.Translator.CommandTimeout.Value;
                }
                int rowsAffected;
                if (this._modificationCommandTree.HasReader)
                {
                    rowsAffected = 0;
                    using (DbDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).WithCurrentCulture <DbDataReader>())
                    {
                        if (await reader.ReadAsync(cancellationToken).WithCurrentCulture <bool>())
                        {
                            ++rowsAffected;
                            IBaseList <EdmMember> members = TypeHelpers.GetAllStructuralMembers((EdmType)this.CurrentValues.StructuralType);
                            for (int ordinal = 0; ordinal < reader.FieldCount; ++ordinal)
                            {
                                string    columnName = reader.GetName(ordinal);
                                EdmMember member     = members[columnName];
                                object    value;
                                if (Helper.IsSpatialType(member.TypeUsage))
                                {
                                    if (!await reader.IsDBNullAsync(ordinal, cancellationToken).WithCurrentCulture <bool>())
                                    {
                                        value = await SpatialHelpers.GetSpatialValueAsync(this.Translator.MetadataWorkspace, reader, member.TypeUsage, ordinal, cancellationToken).WithCurrentCulture <object>();

                                        goto label_14;
                                    }
                                }
                                value = await reader.GetFieldValueAsync <object>(ordinal, cancellationToken).WithCurrentCulture <object>();

label_14:
                                int columnOrdinal = members.IndexOf(member);
                                PropagatorResult result = this.CurrentValues.GetMemberValue(columnOrdinal);
                                generatedValues.Add(new KeyValuePair <PropagatorResult, object>(result, value));
                                int identifier = result.Identifier;
                                if (-1 != identifier)
                                {
                                    identifierValues.Add(identifier, value);
                                }
                            }
                        }
                        await CommandHelper.ConsumeReaderAsync(reader, cancellationToken).WithCurrentCulture();
                    }
                }
                else
                {
                    rowsAffected = await command.ExecuteNonQueryAsync(cancellationToken).WithCurrentCulture <int>();
                }
                num = (long)rowsAffected;
            }
            return(num);
        }
        // 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 == ResultColumns)
            {
                ResultColumns = new List<KeyValuePair<string, PropagatorResult>>(initializeSize);
            }
            ResultColumns.Add(new KeyValuePair<string, PropagatorResult>(columnName, result));

            var identifier = result.Identifier;
            if (PropagatorResult.NullIdentifier != identifier)
            {
                if (translator.KeyManager.HasPrincipals(identifier))
                {
                    throw new InvalidOperationException(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
            var parameter = _dbCommand.Parameters[parameterBinding.Parameter.Name];
            var parameterType = parameterBinding.Parameter.TypeUsage;
            var 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)
            var identifier = result.Identifier;
            if (PropagatorResult.NullIdentifier != identifier)
            {
                const int initialSize = 2; // expect on average less than two input identifiers per command
                if (null == _inputIdentifiers)
                {
                    _inputIdentifiers = new List<KeyValuePair<int, DbParameter>>(initialSize);
                }
                foreach (var principal in translator.KeyManager.GetPrincipals(identifier))
                {
                    _inputIdentifiers.Add(new KeyValuePair<int, DbParameter>(principal, parameter));
                }
            }
        }
示例#38
0
            public void Returns_rows_affected_when_there_are_result_columns()
            {
                var mockPrimitiveType = new Mock <PrimitiveType>();

                mockPrimitiveType.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.PrimitiveType);
                mockPrimitiveType.Setup(m => m.PrimitiveTypeKind).Returns(PrimitiveTypeKind.Int32);
                mockPrimitiveType.Setup(m => m.DataSpace).Returns(DataSpace.CSpace);
                var edmProperty = new EdmProperty("property", TypeUsage.Create(mockPrimitiveType.Object));

                var entityType = new EntityType("", "", DataSpace.CSpace, Enumerable.Empty <string>(), new[] { edmProperty });

                entityType.SetReadOnly();

                var stateEntry = new ExtractedStateEntry(
                    EntityState.Unchanged,
                    PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0),
                    PropagatorResult.CreateStructuralValue(
                        new[] { PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value: 0) },
                        entityType,
                        isModified: false),
                    new Mock <IEntityStateEntry>().Object);

                var updateTranslatorMock = new Mock <UpdateTranslator>();

                updateTranslatorMock.Setup(m => m.CommandTimeout).Returns(() => null);
                var entityConnection = new Mock <EntityConnection>().Object;

                updateTranslatorMock.Setup(m => m.Connection).Returns(entityConnection);
                updateTranslatorMock.Setup(m => m.InterceptionContext).Returns(new DbInterceptionContext());

                var dbCommandMock = new Mock <DbCommand>();
                var stateEntries  = new ReadOnlyCollection <IEntityStateEntry>(new List <IEntityStateEntry>());

                var mockFunctionUpdateCommand = new Mock <FunctionUpdateCommand>(
                    updateTranslatorMock.Object, stateEntries, stateEntry, dbCommandMock.Object)
                {
                    CallBase = true
                };

                var dbValue          = 66;
                var dbDataReaderMock = new Mock <DbDataReader>();

                dbDataReaderMock.Setup(m => m.GetValue(It.IsAny <int>())).Returns(dbValue);
                var rowsToRead = 2;

                dbDataReaderMock.Setup(m => m.Read()).Returns(
                    () =>
                {
                    rowsToRead--;
                    return(rowsToRead > 0);
                });
                dbCommandMock.Protected().Setup <DbDataReader>("ExecuteDbDataReader", CommandBehavior.SequentialAccess).Returns(
                    dbDataReaderMock.Object);

                var timesSetInputIdentifiers = 0;
                var identifierValues         = new Dictionary <int, object>();

                mockFunctionUpdateCommand.Setup(m => m.SetInputIdentifiers(It.IsAny <Dictionary <int, object> >()))
                .Callback <Dictionary <int, object> >(
                    identifierValuesPassed =>
                {
                    timesSetInputIdentifiers++;
                    Assert.Same(identifierValues, identifierValuesPassed);
                });

                var generatedValues        = new List <KeyValuePair <PropagatorResult, object> >();
                var mockObjectStateManager = new Mock <ObjectStateManager>();
                var objectStateEntryMock   = new Mock <ObjectStateEntry>(mockObjectStateManager.Object, null, EntityState.Unchanged);
                var currentValueRecordMock = new Mock <CurrentValueRecord>(objectStateEntryMock.Object);

                var idColumn = new KeyValuePair <string, PropagatorResult>(
                    "ID",
                    PropagatorResult.CreateServerGenSimpleValue(
                        PropagatorFlags.NoFlags, /*value:*/ 0, currentValueRecordMock.Object, recordOrdinal: 0));

                mockFunctionUpdateCommand.Protected().Setup <List <KeyValuePair <string, PropagatorResult> > >("ResultColumns")
                .Returns((new[] { idColumn }).ToList());

                var rowsAffectedResult = mockFunctionUpdateCommand.Object.Execute(identifierValues, generatedValues);

                Assert.Equal(1, rowsAffectedResult);
                Assert.Equal(1, timesSetInputIdentifiers);
                Assert.Equal(1, generatedValues.Count);
                Assert.Same(idColumn.Value, generatedValues[0].Key);
                Assert.Equal(dbValue, generatedValues[0].Value);
            }
        // Note that this is called only for association ends. Entities have key values inline.
        private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey)
        {
            // get metadata for key
            var entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType;
            var keyRowType = entityType.GetKeyRowType();

            var keyMetadata = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType);
            var keyMemberCount = keyRowType.Properties.Count;
            var keyValues = new PropagatorResult[keyMemberCount];

            for (var ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++)
            {
                EdmMember keyMember = keyRowType.Properties[ordinal];
                // retrieve information about this key value
                var keyMemberInformation = keyMetadata.m_memberMap[ordinal];

                var keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count);

                object keyValue = null;
                if (entityKey.IsTemporary)
                {
                    // If the EntityKey is temporary, we need to retrieve the appropriate
                    // key value from the entity itself (or in this case, the IEntityStateEntry).
                    var entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey);
                    Debug.Assert(
                        entityEntry.State == EntityState.Added,
                        "The corresponding entry for a temp EntityKey should be in the Added State.");
                    keyValue = entityEntry.CurrentValues[keyMember.Name];
                }
                else
                {
                    // Otherwise, we extract the value from within the EntityKey.
                    keyValue = entityKey.FindValueByName(keyMember.Name);
                }
                Debug.Assert(keyValue != null, "keyValue should've been retrieved.");

                // construct propagator result
                keyValues[ordinal] = PropagatorResult.CreateKeyValue(
                    keyMemberInformation.Flags,
                    keyValue,
                    stateEntry,
                    keyIdentifier);

                // see UpdateTranslator.Identifiers for information on key identifiers and ordinals
            }

            return PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false);
        }
 internal static PropagatorResult CreateStructuralValue(PropagatorResult[] values, StructuralType structuralType, bool isModified)
 {
     if (isModified)
     {
         return new StructuralValue(values, structuralType);
     }
     else
     {
         return new UnmodifiedStructuralValue(values, structuralType);
     }
 }
            /// <summary>
            ///     Specialization of <see cref="CreatePlaceholder" /> for a relationship set extent.
            /// </summary>
            /// <param name="associationSet"> </param>
            /// <returns> </returns>
            private PropagatorResult CreateAssociationSetPlaceholder(AssociationSet associationSet)
            {
                DebugCheck.NotNull(associationSet);

                var endMetadata = associationSet.ElementType.AssociationEndMembers;
                var endReferenceValues = new PropagatorResult[endMetadata.Count];

                // Create a reference expression for each end in the relationship
                for (var endOrdinal = 0; endOrdinal < endMetadata.Count; endOrdinal++)
                {
                    var end = endMetadata[endOrdinal];
                    var entityType = (EntityType)((RefType)end.TypeUsage.EdmType).ElementType;

                    // Retrieve key values for this end
                    var keyValues = new PropagatorResult[entityType.KeyMembers.Count];
                    for (var memberOrdinal = 0; memberOrdinal < entityType.KeyMembers.Count; memberOrdinal++)
                    {
                        var keyMember = entityType.KeyMembers[memberOrdinal];
                        var keyValue = CreateMemberPlaceholder(keyMember);
                        keyValues[memberOrdinal] = keyValue;
                    }

                    var endType = entityType.GetKeyRowType();
                    var refKeys = PropagatorResult.CreateStructuralValue(keyValues, endType, false);

                    endReferenceValues[endOrdinal] = refKeys;
                }

                var result = PropagatorResult.CreateStructuralValue(endReferenceValues, associationSet.ElementType, false);
                return result;
            }
            internal StructuralValue(PropagatorResult[] values, StructuralType structuralType)
            {
                Debug.Assert(null != structuralType);
                Debug.Assert(null != values);
                Debug.Assert(values.Length == TypeHelpers.GetAllStructuralMembers(structuralType).Count);

                m_values = values;
                m_structuralType = structuralType;
            }
            // Find "sanctioned" default value
            internal static void GetPropagatorResultForPrimitiveType(PrimitiveType primitiveType, out PropagatorResult result)
            {
                object value;
                if (!TryGetDefaultValue(primitiveType, out value))
                {
                    // If none exists, default to lowest common denominator for constants
                    value = default(byte);
                }

                // Return a new constant expression flagged as unknown since the value is only there for
                // show. (Not entirely for show, because null constraints may require a value for a record,
                // whether that record is a placeholder or not).
                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, value);
            }
 internal virtual PropagatorResult Merge(KeyManager keyManager, PropagatorResult other)
 {
     throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UpdatePipelineResultRequestInvalid, 0, "PropagatorResult.Merge");
 }
示例#45
0
 protected UpdateCommand(UpdateTranslator translator, PropagatorResult originalValues, PropagatorResult currentValues)
 {
     OriginalValues = originalValues;
     CurrentValues  = currentValues;
     Translator     = translator;
 }
        // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the
        // value is null, creates an IsNull expression
        // Requires: all arguments are set
        private DbExpression GenerateEqualityExpression(DbExpressionBinding target, EdmProperty property, PropagatorResult value)
        {
            DebugCheck.NotNull(target);
            DebugCheck.NotNull(property);
            DebugCheck.NotNull(value);

            var propertyExpression = GeneratePropertyExpression(target, property);
            var valueExpression = GenerateValueExpression(property, value);
            if (valueExpression.ExpressionKind
                == DbExpressionKind.Null)
            {
                return propertyExpression.IsNull();
            }
            return propertyExpression.Equal(valueExpression);
        }
        // Extracts key constants from the given row.
        private PropagatorResult[] GetKeyConstants(PropagatorResult row)
        {
            var keyConstants = new PropagatorResult[m_keyOrdinals.Length];
            for (var i = 0; i < m_keyOrdinals.Length; i++)
            {
                var constant = row.GetMemberValue(m_keyOrdinals[i]);

                keyConstants[i] = constant;
            }
            return keyConstants;
        }
        /// <summary>
        ///     Determines predicate used to identify a row in a table.
        /// </summary>
        /// <remarks>
        ///     Columns are included in the list when:
        ///     <list>
        ///         <item>They are keys for the table</item>
        ///         <item>They are concurrency values</item>
        ///     </list>
        /// </remarks>
        /// <param name="target"> Expression binding representing the table containing the row </param>
        /// <param name="referenceRow"> Values for the row being located. </param>
        /// <param name="current"> Values being updated (may be null). </param>
        /// <param name="processor"> Context for the table containing the row. </param>
        /// <param name="rowMustBeTouched"> Output parameter indicating whether a row must be touched (whether it's being modified or not) because it contains a concurrency value </param>
        /// <returns> Column/value pairs. </returns>
        private DbExpression BuildPredicate(
            DbExpressionBinding target, PropagatorResult referenceRow, PropagatorResult current,
            TableChangeProcessor processor, ref bool rowMustBeTouched)
        {
            var whereClauses = new Dictionary<EdmProperty, PropagatorResult>();

            // add all concurrency tokens (note that keys are always concurrency tokens as well)
            var propertyOrdinal = 0;
            foreach (var member in processor.Table.ElementType.Properties)
            {
                // members and result values are ordinally aligned
                var expectedValue = referenceRow.GetMemberValue(propertyOrdinal);
                var newValue = null == current ? null : current.GetMemberValue(propertyOrdinal);

                // check if the rowMustBeTouched value should be set to true (if it isn't already
                // true and we've come across a concurrency value)
                if (!rowMustBeTouched
                    &&
                    (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue) ||
                     HasFlag(newValue, PropagatorFlags.ConcurrencyValue)))
                {
                    rowMustBeTouched = true;
                }

                // determine if this is a concurrency value
                if (!whereClauses.ContainsKey(member)
                    && // don't add to the set clause twice
                    (HasFlag(expectedValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key) ||
                     HasFlag(newValue, PropagatorFlags.ConcurrencyValue | PropagatorFlags.Key))) // tagged as concurrency value
                {
                    whereClauses.Add(member, expectedValue);
                }
                propertyOrdinal++;
            }

            // Build a binary AND expression tree from the clauses
            DbExpression predicate = null;
            foreach (var clause in whereClauses)
            {
                var clauseExpression = GenerateEqualityExpression(target, clause.Key, clause.Value);
                if (null == predicate)
                {
                    predicate = clauseExpression;
                }
                else
                {
                    predicate = predicate.And(clauseExpression);
                }
            }

            Debug.Assert(null != predicate, "some predicate term must exist");

            return predicate;
        }
 protected PropagatorResult[] ReplaceValues(Func<PropagatorResult, PropagatorResult> map)
 {
     var newValues = new PropagatorResult[m_values.Length];
     var hasChange = false;
     for (var i = 0; i < newValues.Length; i++)
     {
         var newValue = m_values[i].Replace(map);
         if (!ReferenceEquals(newValue, m_values[i]))
         {
             hasChange = true;
         }
         newValues[i] = newValue;
     }
     return hasChange ? newValues : null;
 }
示例#50
0
        // 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 == ResultColumns)
            {
                ResultColumns = new List <KeyValuePair <string, PropagatorResult> >(initializeSize);
            }
            ResultColumns.Add(new KeyValuePair <string, PropagatorResult>(columnName, result));

            var identifier = result.Identifier;

            if (PropagatorResult.NullIdentifier != identifier)
            {
                if (translator.KeyManager.HasPrincipals(identifier))
                {
                    throw new InvalidOperationException(Strings.Update_GeneratedDependent(columnName));
                }

                // register output identifier to enable fix-up and dependency tracking
                AddOutputIdentifier(columnName, identifier);
            }
        }
        private void DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other)
        {
            var keyManager = compiler.m_translator.KeyManager;
            var otherKey   = new CompositeKey(GetKeyConstants(other));

            // determine if the conflict is due to shared principal key values
            var sharedPrincipal = true;

            for (var i = 0; sharedPrincipal && i < key.KeyComponents.Length; i++)
            {
                var identifier1 = key.KeyComponents[i].Identifier;
                var identifier2 = otherKey.KeyComponents[i].Identifier;

                if (!keyManager.GetPrincipals(identifier1).Intersect(keyManager.GetPrincipals(identifier2)).Any())
                {
                    sharedPrincipal = false;
                }
            }

            if (sharedPrincipal)
            {
                // if the duplication is due to shared principals, there is a duplicate key exception
                var stateEntries = SourceInterpreter.GetAllStateEntries(change, compiler.m_translator, m_table)
                                   .Concat(SourceInterpreter.GetAllStateEntries(other, compiler.m_translator, m_table));
                throw new UpdateException(Strings.Update_DuplicateKeys, null, stateEntries.Cast <ObjectStateEntry>().Distinct());
            }
            else
            {
                // if there are no shared principals, it implies that common dependents are the problem
                HashSet <IEntityStateEntry> commonDependents = null;
                foreach (var keyValue in key.KeyComponents.Concat(otherKey.KeyComponents))
                {
                    var dependents = new HashSet <IEntityStateEntry>();
                    foreach (var dependentId in keyManager.GetDependents(keyValue.Identifier))
                    {
                        PropagatorResult dependentResult;
                        if (keyManager.TryGetIdentifierOwner(dependentId, out dependentResult)
                            &&
                            null != dependentResult.StateEntry)
                        {
                            dependents.Add(dependentResult.StateEntry);
                        }
                    }
                    if (null == commonDependents)
                    {
                        commonDependents = new HashSet <IEntityStateEntry>(dependents);
                    }
                    else
                    {
                        commonDependents.IntersectWith(dependents);
                    }
                }

                // to ensure the exception shape is consistent with constraint violations discovered while processing
                // commands (a more conventional scenario in which different tables are contributing principal values)
                // wrap a DataConstraintException in an UpdateException
                throw new UpdateException(
                          Strings.Update_GeneralExecutionException,
                          new ConstraintException(Strings.Update_ReferentialConstraintIntegrityViolation),
                          commonDependents.Cast <ObjectStateEntry>().Distinct());
            }
        }
 internal UnmodifiedStructuralValue(PropagatorResult[] values, StructuralType structuralType)
     : base(values, structuralType)
 {
 }
示例#53
0
        internal override async Task <long> ExecuteAsync(
            Dictionary <int, object> identifierValues,
            List <KeyValuePair <PropagatorResult, object> > generatedValues,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            EntityConnection connection = this.Translator.Connection;

            this._dbCommand.Transaction = connection.CurrentTransaction == null ? (DbTransaction)null : connection.CurrentTransaction.StoreTransaction;
            this._dbCommand.Connection  = connection.StoreConnection;
            if (this.Translator.CommandTimeout.HasValue)
            {
                this._dbCommand.CommandTimeout = this.Translator.CommandTimeout.Value;
            }
            this.SetInputIdentifiers(identifierValues);
            long rowsAffected;

            if (this.ResultColumns != null)
            {
                rowsAffected = 0L;
                IBaseList <EdmMember> members = TypeHelpers.GetAllStructuralMembers((EdmType)this.CurrentValues.StructuralType);
                using (DbDataReader reader = await this._dbCommand.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken).WithCurrentCulture <DbDataReader>())
                {
                    if (await reader.ReadAsync(cancellationToken).WithCurrentCulture <bool>())
                    {
                        ++rowsAffected;
                        foreach (KeyValuePair <int, PropagatorResult> keyValuePair in (IEnumerable <KeyValuePair <int, PropagatorResult> >) this.ResultColumns.Select <KeyValuePair <string, PropagatorResult>, KeyValuePair <int, PropagatorResult> >((Func <KeyValuePair <string, PropagatorResult>, KeyValuePair <int, PropagatorResult> >)(r => new KeyValuePair <int, PropagatorResult>(this.GetColumnOrdinal(this.Translator, reader, r.Key), r.Value))).OrderBy <KeyValuePair <int, PropagatorResult>, int>((Func <KeyValuePair <int, PropagatorResult>, int>)(r => r.Key)))
                        {
                            int       columnOrdinal = keyValuePair.Key;
                            TypeUsage columnType    = members[keyValuePair.Value.RecordOrdinal].TypeUsage;
                            object    value;
                            if (Helper.IsSpatialType(columnType))
                            {
                                if (!await reader.IsDBNullAsync(columnOrdinal, cancellationToken).WithCurrentCulture <bool>())
                                {
                                    value = await SpatialHelpers.GetSpatialValueAsync(this.Translator.MetadataWorkspace, reader, columnType, columnOrdinal, cancellationToken).WithCurrentCulture <object>();

                                    goto label_14;
                                }
                            }
                            value = await reader.GetFieldValueAsync <object>(columnOrdinal, cancellationToken).WithCurrentCulture <object>();

label_14:
                            PropagatorResult result = keyValuePair.Value;
                            generatedValues.Add(new KeyValuePair <PropagatorResult, object>(result, value));
                            int identifier = result.Identifier;
                            if (-1 != identifier)
                            {
                                identifierValues.Add(identifier, value);
                            }
                        }
                    }
                    await CommandHelper.ConsumeReaderAsync(reader, cancellationToken).WithCurrentCulture();
                }
            }
            else
            {
                rowsAffected = (long)await this._dbCommand.ExecuteNonQueryAsync(cancellationToken).WithCurrentCulture <int>();
            }
            return(this.GetRowsAffected(rowsAffected, this.Translator));
        }
 internal bool TryGetIdentifierOwner(int identifier, out PropagatorResult owner)
 {
     owner = this._identifiers[identifier].Owner;
     return(null != owner);
 }
            /// <summary>
            ///     Produce a tuple containing joined rows.
            /// </summary>
            /// <param name="left"> Left row. </param>
            /// <param name="right"> Right row. </param>
            /// <param name="leftKey"> Key used to join left element. </param>
            /// <param name="rightKey"> Key used to join right element. </param>
            /// <param name="result"> Result change node; used for type information. </param>
            /// <returns> Result of joining the input rows. </returns>
            private PropagatorResult CreateResultTuple(
                Tuple<CompositeKey, PropagatorResult> left, Tuple<CompositeKey, PropagatorResult> right, ChangeNode result)
            {
                // using ref compare to avoid triggering value based
                var leftKey = left.Item1;
                var rightKey = right.Item1;
                Dictionary<PropagatorResult, PropagatorResult> map = null;
                if (!ReferenceEquals(null, leftKey)
                    &&
                    !ReferenceEquals(null, rightKey)
                    &&
                    !ReferenceEquals(leftKey, rightKey))
                {
                    // Merge key values from the left and the right (since they're equal, there's a possibility we'll
                    // project values only from the left or the right hand side and lose important context.)
                    var mergedKey = leftKey.Merge(m_parent.m_updateTranslator.KeyManager, rightKey);
                    // create a dictionary so that we can replace key values with merged key values (carrying context
                    // from both sides)
                    map = new Dictionary<PropagatorResult, PropagatorResult>();
                    for (var i = 0; i < leftKey.KeyComponents.Length; i++)
                    {
                        map[leftKey.KeyComponents[i]] = mergedKey.KeyComponents[i];
                        map[rightKey.KeyComponents[i]] = mergedKey.KeyComponents[i];
                    }
                }

                var joinRecordValues = new PropagatorResult[2];
                joinRecordValues[0] = left.Item2;
                joinRecordValues[1] = right.Item2;
                var join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false);

                // replace with merged key values as appropriate
                if (null != map)
                {
                    PropagatorResult replacement;
                    join = join.Replace(original => map.TryGetValue(original, out replacement) ? replacement : original);
                }

                return join;
            }
 // Effects: returns true iff. the input propagator result has some flag defined in "flags"
 // Requires: input is set
 private static bool HasFlag(PropagatorResult input, PropagatorFlags flags)
 {
     if (null == input)
     {
         return false;
     }
     return (PropagatorFlags.NoFlags != (flags & input.PropagatorFlags));
 }
            // Walks through all parameter bindings in the function mapping and binds the parameters to the
            // requested properties of the given state entry.
            private static void BindFunctionParameters(
                UpdateTranslator translator, ExtractedStateEntry stateEntry, ModificationFunctionMapping functionMapping,
                FunctionUpdateCommand command, Dictionary <AssociationEndMember, IEntityStateEntry> currentReferenceEnds,
                Dictionary <AssociationEndMember, IEntityStateEntry> originalReferenceEnds)
            {
                // bind all parameters
                foreach (var parameterBinding in functionMapping.ParameterBindings)
                {
                    PropagatorResult result;

                    // extract value
                    if (null != parameterBinding.MemberPath.AssociationSetEnd)
                    {
                        // find the relationship entry corresponding to the navigation
                        var endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember;
                        IEntityStateEntry relationshipEntry;
                        var hasTarget = parameterBinding.IsCurrent
                                            ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry)
                                            : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry);
                        if (!hasTarget)
                        {
                            if (endMember.RelationshipMultiplicity
                                == RelationshipMultiplicity.One)
                            {
                                var entitySetName      = stateEntry.Source.EntitySet.Name;
                                var associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name;
                                throw new UpdateException(
                                          Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName), null,
                                          command.GetStateEntries(translator).Cast <ObjectStateEntry>().Distinct());
                            }
                            else
                            {
                                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null);
                            }
                        }
                        else
                        {
                            // get the actual value
                            var relationshipResult = parameterBinding.IsCurrent
                                                         ? translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                                relationshipEntry, ModifiedPropertiesBehavior.AllModified)
                                                         : translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                                relationshipEntry, ModifiedPropertiesBehavior.AllModified);
                            var endResult   = relationshipResult.GetMemberValue(endMember);
                            var 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 (var i = parameterBinding.MemberPath.Members.Count; i > 0;)
                        {
                            --i;
                            var member = parameterBinding.MemberPath.Members[i];
                            result = result.GetMemberValue(member);
                        }
                    }

                    // create DbParameter
                    command.SetParameterValue(result, parameterBinding, translator);
                }
                // Add rows affected parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
            }
            /// <summary>
            ///     Specialization of <see cref="CreatePlaceholder" /> for an entity set extent.
            /// </summary>
            /// <param name="entitySet"> </param>
            /// <returns> </returns>
            private PropagatorResult CreateEntitySetPlaceholder(EntitySet entitySet)
            {
                DebugCheck.NotNull(entitySet);
                var members = entitySet.ElementType.Properties;
                var memberValues = new PropagatorResult[members.Count];

                for (var ordinal = 0; ordinal < members.Count; ordinal++)
                {
                    var memberValue = CreateMemberPlaceholder(members[ordinal]);
                    memberValues[ordinal] = memberValue;
                }

                var result = PropagatorResult.CreateStructuralValue(memberValues, entitySet.ElementType, false);

                return result;
            }
示例#59
0
        // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the
        // value is null, creates an IsNull expression
        // Requires: all arguments are set
        private DbExpression GenerateEqualityExpression(DbExpressionBinding target, EdmProperty property, PropagatorResult value)
        {
            DebugCheck.NotNull(target);
            DebugCheck.NotNull(property);
            DebugCheck.NotNull(value);

            var propertyExpression = GeneratePropertyExpression(target, property);
            var valueExpression    = GenerateValueExpression(property, value);

            if (valueExpression.ExpressionKind
                == DbExpressionKind.Null)
            {
                return(propertyExpression.IsNull());
            }
            return(propertyExpression.Equal(valueExpression));
        }
        /// <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)
        {
            var structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType;
            var metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType);
            var key = stateEntry.EntityKey;

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

            return PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified);
        }