Пример #1
0
        /// <summary>
        /// Given a value, returns the value for its principal owner.
        /// </summary>
        internal object GetPrincipalValue(PropagatorResult result)
        {
            int currentIdentifier = result.Identifier;

            if (PropagatorResult.NullIdentifier == currentIdentifier)
            {
                // for non-identifiers, there is nothing to resolve
                return(result.GetSimpleValue());
            }

            // find principals for this value
            bool   first = true;
            object value = null;

            foreach (int principal in GetPrincipals(currentIdentifier))
            {
                PropagatorResult ownerResult = _identifiers[principal].Owner;
                if (null != ownerResult)
                {
                    if (first)
                    {
                        // result is taken from the first principal
                        value = ownerResult.GetSimpleValue();
                        first = false;
                    }
                    else
                    {
                        // subsequent results are validated for consistency with the first
                        if (!ByValueEqualityComparer.Default.Equals(value, ownerResult.GetSimpleValue()))
                        {
                            throw EntityUtil.Constraint(System.Data.Entity.Strings.Update_ReferentialConstraintIntegrityViolation);
                        }
                    }
                }
            }

            if (first)
            {
                // if there are no principals, return the current value directly
                value = result.GetSimpleValue();
            }
            return(value);
        }
Пример #2
0
            // determines equality by comparing each key component
            public bool Equals(CompositeKey left, CompositeKey right)
            {
                // Short circuit the comparison if we know the other reference is equivalent
                if (object.ReferenceEquals(left, right))
                {
                    return(true);
                }

                // If either side is null, return false order (both can't be null because of
                // the previous check)
                if (null == left || null == right)
                {
                    return(false);
                }

                Debug.Assert(null != left.KeyComponents && null != right.KeyComponents,
                             "(Update/JoinPropagator) CompositeKey must be initialized");

                if (left.KeyComponents.Length != right.KeyComponents.Length)
                {
                    return(false);
                }

                for (int i = 0; i < left.KeyComponents.Length; i++)
                {
                    PropagatorResult leftValue  = left.KeyComponents[i];
                    PropagatorResult rightValue = right.KeyComponents[i];

                    // if both side are identifiers, check if they're the same or one is constrained by the
                    // other (if there is a dependent-principal relationship, they get fixed up to the same
                    // value)
                    if (leftValue.Identifier != PropagatorResult.NullIdentifier)
                    {
                        if (rightValue.Identifier == PropagatorResult.NullIdentifier ||
                            _manager.GetCliqueIdentifier(leftValue.Identifier) != _manager.GetCliqueIdentifier(rightValue.Identifier))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        if (rightValue.Identifier != PropagatorResult.NullIdentifier ||
                            !ByValueEqualityComparer.Default.Equals(leftValue.GetSimpleValue(), rightValue.GetSimpleValue()))
                        {
                            return(false);
                        }
                    }
                }

                return(true);
            }
Пример #3
0
 // Gets the value to use for hash code
 private int GetComponentHashCode(PropagatorResult keyComponent)
 {
     if (keyComponent.Identifier == PropagatorResult.NullIdentifier)
     {
         // no identifier exists for this key component, so use the actual key
         // value
         Debug.Assert(null != keyComponent && null != keyComponent,
                      "key value must not be null");
         return(ByValueEqualityComparer.Default.GetHashCode(keyComponent.GetSimpleValue()));
     }
     else
     {
         // use ID for FK graph clique (this ensures that keys fixed up to the same
         // value based on a constraint will have the same hash code)
         return(_manager.GetCliqueIdentifier(keyComponent.Identifier).GetHashCode());
     }
 }
Пример #4
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)
        {
            Dictionary <EdmProperty, PropagatorResult>  setClauses         = new Dictionary <EdmProperty, PropagatorResult>();
            List <KeyValuePair <string, DbExpression> > returningArguments = new List <KeyValuePair <string, DbExpression> >();

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

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

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

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

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

                bool omitFromSetList = false;

                Debug.Assert(propertyResult.IsSimple);

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

                // check if this value should be omitted
                PropagatorFlags 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
                StoreGeneratedPattern genPattern = MetadataHelper.GetStoreGeneratedPattern(property);
                bool isServerGen = genPattern == StoreGeneratedPattern.Computed ||
                                   (insertMode && genPattern == StoreGeneratedPattern.Identity);
                if (isServerGen)
                {
                    DbPropertyExpression propertyExpression = target.Variable.Property(property);
                    returningArguments.Add(new KeyValuePair <string, DbExpression>(property.Name, propertyExpression));

                    // check if this is a server generated identifier
                    int identifier = propertyResult.Identifier;
                    if (PropagatorResult.NullIdentifier != identifier)
                    {
                        if (m_translator.KeyManager.HasPrincipals(identifier))
                        {
                            throw EntityUtil.InvalidOperation(System.Data.Entity.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 EntityUtil.NotSupported(System.Data.Entity.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");
                    PropagatorResult 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 EntityUtil.InvalidOperation(System.Data.Entity.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
            List <DbModificationClause> result = new List <DbModificationClause>(setClauses.Count);

            foreach (KeyValuePair <EdmProperty, PropagatorResult> setClause in setClauses)
            {
                EdmProperty property = setClause.Key;

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

            return(result);
        }