UpdateCommand.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / UpdateCommand.cs / 1305376 / UpdateCommand.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Metadata.Edm; 
using System.Data.Common;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics; 
using System.Globalization;
using System.Data.Common.Utils; 
using System.Data.Common.CommandTrees; 
using System.Data.Objects;
using System.Linq; 
using System.Data.EntityClient;
using System.Threading;
namespace System.Data.Mapping.Update.Internal
{ 
    internal enum UpdateCommandKind
    { 
        Dynamic, 
        Function,
    } 

    /// 
    /// Class storing the result of compiling an instance DML command.
    ///  
    internal abstract class UpdateCommand : IComparable, IEquatable
    { 
        protected UpdateCommand(PropagatorResult originalValues, PropagatorResult currentValues) 
        {
            m_originalValues = originalValues; 
            m_currentValues = currentValues;
        }

        private readonly PropagatorResult m_originalValues; 
        private readonly PropagatorResult m_currentValues;
 
        // When it is not possible to order two commands based on their contents, we assign an 'ordering identifier' 
        // so that one will consistently precede the other.
        private static int s_orderingIdentifierCounter; 
        private int m_orderingIdentifier;

        /// 
        /// Gets all identifiers (key values basically) generated by this command. For instance, 
        /// @@IDENTITY values.
        ///  
        internal abstract IEnumerable OutputIdentifiers { get; } 

        ///  
        /// Gets all identifiers required by this command.
        /// 
        internal abstract IEnumerable InputIdentifiers { get; }
 
        /// 
        /// Gets table (if any) associated with the current command. FunctionUpdateCommand has no table. 
        ///  
        internal virtual EntitySet Table
        { 
            get
            {
                return null;
            } 
        }
 
        ///  
        /// Gets type of command.
        ///  
        internal abstract UpdateCommandKind Kind
        {
            get;
        } 

        ///  
        /// Gets original values of row/entity handled by this command. 
        /// 
        internal PropagatorResult OriginalValues { get { return m_originalValues; } } 

        /// 
        /// Gets current values of row/entity handled by this command.
        ///  
        internal PropagatorResult CurrentValues { get { return m_currentValues; } }
 
        ///  
        /// Yields all state entries contributing to this command. Used for error reporting.
        ///  
        /// Translator context.
        /// Related state entries.
        internal abstract IList GetStateEntries(UpdateTranslator translator);
 
        /// 
        /// Determines model level dependencies for the current command. Dependencies are based 
        /// on the model operations performed by the command (adding or deleting entities or relationships). 
        /// 
        internal void GetRequiredAndProducedEntities(UpdateTranslator translator, 
            KeyToListMap addedEntities,
            KeyToListMap deletedEntities,
            KeyToListMap addedRelationships,
            KeyToListMap deletedRelationships) 
        {
            IList stateEntries = GetStateEntries(translator); 
 
            foreach (IEntityStateEntry stateEntry in stateEntries)
            { 
                if (!stateEntry.IsRelationship)
                {
                    if (stateEntry.State == EntityState.Added)
                    { 
                        addedEntities.Add(stateEntry.EntityKey, this);
                    } 
                    else if (stateEntry.State == EntityState.Deleted) 
                    {
                        deletedEntities.Add(stateEntry.EntityKey, this); 
                    }
                }
            }
 
            // process foreign keys
            if (null != this.OriginalValues) 
            { 
                // if a foreign key being deleted, it 'frees' or 'produces' the referenced key
                AddReferencedEntities(translator, this.OriginalValues, deletedRelationships); 
            }
            if (null != this.CurrentValues)
            {
                // if a foreign key is being added, if requires the referenced key 
                AddReferencedEntities(translator, this.CurrentValues, addedRelationships);
            } 
 
            // process relationships
            foreach (IEntityStateEntry stateEntry in stateEntries) 
            {
                if (stateEntry.IsRelationship)
                {
                    // only worry about the relationship if it is being added or deleted 
                    bool isAdded = stateEntry.State == EntityState.Added;
                    if (isAdded || stateEntry.State == EntityState.Deleted) 
                    { 
                        DbDataRecord record = isAdded ? (DbDataRecord)stateEntry.CurrentValues : stateEntry.OriginalValues;
                        Debug.Assert(2 == record.FieldCount, "non-binary relationship?"); 
                        EntityKey end1 = (EntityKey)record[0];
                        EntityKey end2 = (EntityKey)record[1];

                        // relationships require the entity when they're added and free the entity when they're deleted... 
                        KeyToListMap affected = isAdded ? addedRelationships : deletedRelationships;
 
                        // both ends are being modified by the relationship 
                        affected.Add(end1, this);
                        affected.Add(end2, this); 
                    }
                }
            }
        } 

        private void AddReferencedEntities(UpdateTranslator translator, PropagatorResult result, KeyToListMap referencedEntities) 
        { 
            foreach (PropagatorResult property in result.GetMemberValues())
            { 
                if (property.IsSimple && property.Identifier != PropagatorResult.NullIdentifier &&
                    (PropagatorFlags.ForeignKey == (property.PropagatorFlags & PropagatorFlags.ForeignKey)))
                {
                    foreach (int principal in translator.KeyManager.GetPrincipals(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);
                        }
                    } 
                }
            } 
        } 

        ///  
        /// Executes the current update command.
        /// 
        /// Translator context.
        /// EntityConnection to use (and implicitly, the EntityTransaction to use). 
        /// Aggregator for identifier values (read for InputIdentifiers; write for
        /// OutputIdentifiers 
        /// Aggregator for server generated values. 
        /// Number of rows affected by the command.
        internal abstract long Execute(UpdateTranslator translator, EntityConnection connection, Dictionary identifierValues, 
            List> generatedValues);

        /// 
        /// Implementation of CompareTo for concrete subclass of UpdateCommand. 
        /// 
        internal abstract int CompareToType(UpdateCommand other); 
 
        /// 
        /// Provides a suggested ordering between two commands. Ensuring a consistent ordering is important to avoid deadlocks 
        /// between two clients because it means locks are acquired in the same order where possible. The ordering criteria are as
        /// follows (and are partly implemented in the CompareToType method). In some cases there are specific secondary
        /// reasons for the order (e.g. operator kind), but for the most case we just care that a consistent ordering
        /// is applied: 
        ///
        /// - The kind of command (dynamic or function). This is an arbitrary criteria. 
        /// - The kind of operator (insert, update, delete). See  for details of the ordering. 
        /// - The target of the modification (table for dynamic, set for function).
        /// - Primary key for the modification (table key for dynamic, entity keys for function). 
        ///
        /// If it is not possible to differentiate between two commands (e.g., where the user is inserting entities with server-generated
        /// primary keys and has not given explicit values), arbitrary ordering identifiers are assigned to the commands to
        /// ensure CompareTo is well-behaved (doesn't return 0 for different commands and suggests consistent ordering). 
        /// 
        public int CompareTo(UpdateCommand other) 
        { 
            // If the commands are the same (by reference), return 0 immediately. Otherwise, we try to find (and eventually
            // force) an ordering between them by returning a value that is non-zero. 
            if (this.Equals(other)) { return 0; }
            Debug.Assert(null != other, "comparing to null UpdateCommand");
            int result = (int)this.Kind - (int)other.Kind;
            if (0 != result) { return result; } 

            // defer to specific type for other comparisons... 
            result = CompareToType(other); 
            if (0 != result) { return result; }
 
            // if the commands are indistinguishable, assign arbitrary identifiers to them to ensure consistent ordering
            unchecked
            {
                if (this.m_orderingIdentifier == 0) 
                {
                    this.m_orderingIdentifier = Interlocked.Increment(ref s_orderingIdentifierCounter); 
                } 
                if (other.m_orderingIdentifier == 0)
                { 
                    other.m_orderingIdentifier = Interlocked.Increment(ref s_orderingIdentifierCounter);
                }

                return this.m_orderingIdentifier - other.m_orderingIdentifier; 
            }
        } 
 
        #region IEquatable: note that we use reference equality
        public bool Equals(UpdateCommand other) 
        {
            return base.Equals(other);
        }
 
        public override bool Equals(object obj)
        { 
            return base.Equals(obj); 
        }
 
        public override int GetHashCode()
        {
            return base.GetHashCode();
        } 
        #endregion
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK