DataContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DLinq / Dlinq / DataContext.cs / 1 / DataContext.cs

                            using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; 
using System.Configuration;
using System.Data; 
using System.Data.Common; 
using System.Globalization;
using System.IO; 
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text; 
using System.Transactions;
using System.Xml; 
 
namespace System.Data.Linq {
    using System.Data.Linq.Mapping; 
    using System.Data.Linq.Provider;
    using System.Diagnostics.CodeAnalysis;

    ///  
    /// Used to specify how a submit should behave when one
    /// or more updates fail due to optimistic concurrency 
    /// conflicts. 
    /// 
    public enum ConflictMode { 
        /// 
        /// Fail immediately when the first change conflict is encountered.
        /// 
        FailOnFirstConflict, 
        /// 
        /// Only fail after all changes have been attempted. 
        ///  
        ContinueOnConflict
    } 

    /// 
    /// Used to specify a value synchronization strategy.
    ///  
    public enum RefreshMode {
        ///  
        /// Keep the current values. 
        /// 
        KeepCurrentValues, 
        /// 
        /// Current values that have been changed are not modified, but
        /// any unchanged values are updated with the current database
        /// values.  No changes are lost in this merge. 
        /// 
        KeepChanges, 
        ///  
        /// All current values are overwritten with current database values,
        /// regardless of whether they have been changed. 
        /// 
        OverwriteCurrentValues
    }
 
    /// 
    /// The DataContext is the source of all entities mapped over a database connection. 
    /// It tracks changes made to all retrieved entities and maintains an 'identity cache' 
    /// that guarantees that entities retrieved more than once are represented using the
    /// same object instance. 
    /// 
    public class DataContext : IDisposable {
        CommonDataServices services;
        IProvider provider; 
        Dictionary tables;
        bool objectTrackingEnabled = true; 
        bool deferredLoadingEnabled = true; 
        bool disposed;
        bool isInSubmitChanges; 
        DataLoadOptions loadOptions;
        ChangeConflictCollection conflicts;

        private DataContext() { 
        }
 
        public DataContext(string fileOrServerOrConnection) { 
            if (fileOrServerOrConnection == null) {
                throw Error.ArgumentNull("fileOrServerOrConnection"); 
            }
            this.InitWithDefaultMapping(fileOrServerOrConnection);
        }
 
        public DataContext(string fileOrServerOrConnection, MappingSource mapping) {
            if (fileOrServerOrConnection == null) { 
                throw Error.ArgumentNull("fileOrServerOrConnection"); 
            }
            if (mapping == null) { 
                throw Error.ArgumentNull("mapping");
            }
            this.Init(fileOrServerOrConnection, mapping);
        } 

        public DataContext(IDbConnection connection) { 
            if (connection == null) { 
                throw Error.ArgumentNull("connection");
            } 
            this.InitWithDefaultMapping(connection);
        }

        public DataContext(IDbConnection connection, MappingSource mapping) { 
            if (connection == null) {
                throw Error.ArgumentNull("connection"); 
            } 
            if (mapping == null) {
                throw Error.ArgumentNull("mapping"); 
            }
            this.Init(connection, mapping);
        }
 
        internal DataContext(DataContext context) {
            if (context == null) { 
                throw Error.ArgumentNull("context"); 
            }
            this.Init(context.Connection, context.Mapping.MappingSource); 
            this.LoadOptions = context.LoadOptions;
            this.Transaction = context.Transaction;
            this.Log = context.Log;
            this.CommandTimeout = context.CommandTimeout; 
        }
 
        #region Dispose\Finalize 
        public void Dispose() {
            this.disposed = true; 
            Dispose(true);
        }
        // Not implementing finalizer here because there are no unmanaged resources
        // to release. See http://msdnwiki.microsoft.com/en-us/mtpswiki/12afb1ea-3a17-4a3f-a1f0-fcdb853e2359.aspx 

        // The bulk of the clean-up code is implemented in Dispose(bool) 
        protected virtual void Dispose(bool disposing) { 
            // Implemented but empty so that derived contexts can implement
            // a finalizer that potentially cleans up unmanaged resources. 
            if (disposing) {
                if (this.provider != null) {
                    this.provider.Dispose();
                    this.provider = null; 
                }
                this.services = null; 
                this.tables = null; 
                this.loadOptions = null;
            } 
        }

        internal void CheckDispose() {
            if (this.disposed) { 
                throw Error.DataContextCannotBeUsedAfterDispose();
            } 
        } 
        #endregion
 
        private void InitWithDefaultMapping(object connection) {
            this.Init(connection, new AttributeMappingSource());
        }
 
        internal object Clone() {
            CheckDispose(); 
            return Activator.CreateInstance(this.GetType(), new object[] { this.Connection, this.Mapping.MappingSource }); 
        }
 
        private void Init(object connection, MappingSource mapping) {
            MetaModel model = mapping.GetModel(this.GetType());
            this.services = new CommonDataServices(this, model);
            this.conflicts = new ChangeConflictCollection(); 

            // determine provider 
            Type providerType; 
            if (model.ProviderType != null) {
                providerType = model.ProviderType; 
            }
            else {
                throw Error.ProviderTypeNull();
            } 

            if (!typeof(IProvider).IsAssignableFrom(providerType)) { 
                throw Error.ProviderDoesNotImplementRequiredInterface(providerType, typeof(IProvider)); 
            }
 
            this.provider = (IProvider)Activator.CreateInstance(providerType);
            this.provider.Initialize(this.services, connection);

            this.tables = new Dictionary(); 
            this.InitTables(this);
        } 
 
        internal void ClearCache() {
            CheckDispose(); 
            this.services.ResetServices();
        }

        internal CommonDataServices Services { 
            get {
                CheckDispose(); 
                return this.services; 
            }
        } 

        /// 
        /// The connection object used by this DataContext when executing queries and commands.
        ///  
        public DbConnection Connection {
            get { 
                CheckDispose(); 
                return this.provider.Connection;
            } 
        }

        /// 
        /// The transaction object used by this DataContext when executing queries and commands. 
        /// 
        public DbTransaction Transaction { 
            get { 
                CheckDispose();
                return this.provider.Transaction; 
            }
            set {
                CheckDispose();
                this.provider.Transaction = value; 
            }
        } 
 
        /// 
        /// The command timeout to use when executing commands. 
        /// 
        public int CommandTimeout {
            get {
                CheckDispose(); 
                return this.provider.CommandTimeout;
            } 
            set { 
                CheckDispose();
                this.provider.CommandTimeout = value; 
            }
        }

        ///  
        /// A text writer used by this DataContext to output information such as query and commands
        /// being executed. 
        ///  
        public TextWriter Log {
            get { 
                CheckDispose();
                return this.provider.Log;
            }
            set { 
                CheckDispose();
                this.provider.Log = value; 
            } 
        }
 
        /// 
        /// True if object tracking is enabled, false otherwise.  Object tracking
        /// includes identity caching and change tracking.  If tracking is turned off,
        /// SubmitChanges and related functionality is disabled.  DeferredLoading is 
        /// also disabled when object tracking is disabled.
        ///  
        public bool ObjectTrackingEnabled { 
            get {
                CheckDispose(); 
                return objectTrackingEnabled;
            }
            set {
                CheckDispose(); 
                if (Services.HasCachedObjects) {
                    throw Error.OptionsCannotBeModifiedAfterQuery(); 
                } 
                objectTrackingEnabled = value;
                if (!objectTrackingEnabled) { 
                    deferredLoadingEnabled = false;
                }
                // force reinitialization of cache/tracking objects
                services.ResetServices(); 
            }
        } 
 
        /// 
        /// True if deferred loading is enabled, false otherwise.  With deferred 
        /// loading disabled, association members return default values and are
        /// not defer loaded.
        /// 
        public bool DeferredLoadingEnabled { 
            get {
                CheckDispose(); 
                return deferredLoadingEnabled; 
            }
            set { 
                CheckDispose();
                if (Services.HasCachedObjects) {
                    throw Error.OptionsCannotBeModifiedAfterQuery();
                } 
                // can't have tracking disabled and deferred loading enabled
                if (!ObjectTrackingEnabled && value) { 
                    throw Error.DeferredLoadingRequiresObjectTracking(); 
                }
                deferredLoadingEnabled = value; 
            }
        }

        ///  
        /// The mapping model used to describe the entities
        ///  
        public MetaModel Mapping { 
            get {
                CheckDispose(); 
                return this.services.Model;
            }
        }
 
        /// 
        /// Verify that change tracking is enabled, and throw an exception 
        /// if it is not. 
        /// 
        internal void VerifyTrackingEnabled() { 
            CheckDispose();
            if (!ObjectTrackingEnabled) {
                throw Error.ObjectTrackingRequired();
            } 
        }
 
        ///  
        /// Verify that submit changes is not occurring
        ///  
        internal void CheckNotInSubmitChanges() {
            CheckDispose();
            if (this.isInSubmitChanges) {
                throw Error.CannotPerformOperationDuringSubmitChanges(); 
            }
        } 
 
        /// 
        /// Verify that submit changes is occurring 
        /// 
        internal void CheckInSubmitChanges() {
            CheckDispose();
            if (!this.isInSubmitChanges) { 
                throw Error.CannotPerformOperationOutsideSubmitChanges();
            } 
        } 

        ///  
        /// Returns the strongly-typed Table object representing a collection of persistent entities.
        /// Use this collection as the starting point for queries.
        /// 
        /// The type of the entity objects. In case of a persistent hierarchy 
        /// the entity specified must be the base type of the hierarchy.
        ///  
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        public Table GetTable() where TEntity : class {
            CheckDispose(); 
            MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));
            if (metaTable == null) {
                throw Error.TypeIsNotMarkedAsTable(typeof(TEntity));
            } 
            ITable table = this.GetTable(metaTable);
            if (table.ElementType != typeof(TEntity)) { 
                throw Error.CouldNotGetTableForSubtype(typeof(TEntity), metaTable.RowType.Type); 
            }
            return (Table)table; 
        }

        /// 
        /// Returns the weakly-typed ITable object representing a collection of persistent entities. 
        /// Use this collection as the starting point for dynamic/runtime-computed queries.
        ///  
        /// The type of the entity objects. In case of a persistent hierarchy 
        /// the entity specified must be the base type of the hierarchy.
        ///  
        public ITable GetTable(Type type) {
            CheckDispose();
            if (type == null) {
                throw Error.ArgumentNull("type"); 
            }
            MetaTable metaTable = this.services.Model.GetTable(type); 
            if (metaTable == null) { 
                throw Error.TypeIsNotMarkedAsTable(type);
            } 
            if (metaTable.RowType.Type != type) {
                throw Error.CouldNotGetTableForSubtype(type, metaTable.RowType.Type);
            }
            return this.GetTable(metaTable); 
        }
 
        private ITable GetTable(MetaTable metaTable) { 
            System.Diagnostics.Debug.Assert(metaTable != null);
            ITable tb; 
            if (!this.tables.TryGetValue(metaTable, out tb)) {
                ValidateTable(metaTable);
                Type tbType = typeof(Table<>).MakeGenericType(metaTable.RowType.Type);
                tb = (ITable)Activator.CreateInstance(tbType, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, new object[] { this, metaTable }, null); 
                this.tables.Add(metaTable, tb);
            } 
            return tb; 
        }
 
        private static void ValidateTable(MetaTable metaTable) {
            // Associations can only be between entities - verify both that both ends of all
            // associations are entities.
            foreach(MetaAssociation assoc in metaTable.RowType.Associations) { 
                if(!assoc.ThisMember.DeclaringType.IsEntity) {
                    throw Error.NonEntityAssociationMapping(assoc.ThisMember.DeclaringType.Type, assoc.ThisMember.Name, assoc.ThisMember.DeclaringType.Type); 
                } 
                if(!assoc.OtherType.IsEntity) {
                    throw Error.NonEntityAssociationMapping(assoc.ThisMember.DeclaringType.Type, assoc.ThisMember.Name, assoc.OtherType.Type); 
                }
            }
        }
 
        private void InitTables(object schema) {
            FieldInfo[] fields = schema.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); 
            foreach (FieldInfo fi in fields) { 
                Type ft = fi.FieldType;
                if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) { 
                    ITable tb = (ITable)fi.GetValue(schema);
                    if (tb == null) {
                        Type rowType = ft.GetGenericArguments()[0];
                        tb = this.GetTable(rowType); 
                        fi.SetValue(schema, tb);
                    } 
                } 
            }
        } 

        /// 
        /// Internal method that can be accessed by tests to retrieve the provider
        /// The IProvider result can then be cast to the actual provider to call debug methods like 
        ///   CheckQueries, QueryCount, EnableCacheLookup
        ///  
        internal IProvider Provider { 
            get {
                CheckDispose(); 
                return this.provider;
            }
        }
 
        /// 
        /// Returns true if the database specified by the connection object exists. 
        ///  
        /// 
        public bool DatabaseExists() { 
            CheckDispose();
            return this.provider.DatabaseExists();
        }
 
        /// 
        /// Creates a new database instance (catalog or file) at the location specified by the connection 
        /// using the metadata encoded within the entities or mapping file. 
        /// 
        public void CreateDatabase() { 
            CheckDispose();
            this.provider.CreateDatabase();
        }
 
        /// 
        /// Deletes the database instance at the location specified by the connection. 
        ///  
        public void DeleteDatabase() {
            CheckDispose(); 
            this.provider.DeleteDatabase();
        }

        ///  
        /// Submits one or more commands to the database reflecting the changes made to the retreived entities.
        /// If a transaction is not already specified one will be created for the duration of this operation. 
        /// If a change conflict is encountered a ChangeConflictException will be thrown. 
        /// 
        public void SubmitChanges() { 
            CheckDispose();
            SubmitChanges(ConflictMode.FailOnFirstConflict);
        }
 
        /// 
        /// Submits one or more commands to the database reflecting the changes made to the retreived entities. 
        /// If a transaction is not already specified one will be created for the duration of this operation. 
        /// If a change conflict is encountered a ChangeConflictException will be thrown.
        /// You can override this method to implement common conflict resolution behaviors. 
        /// 
        /// Determines how SubmitChanges handles conflicts.
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "[....]: In the middle of attempting to rollback a transaction, outer transaction is thrown.")]
        public virtual void SubmitChanges(ConflictMode failureMode) { 
            CheckDispose();
            CheckNotInSubmitChanges(); 
            VerifyTrackingEnabled(); 
            this.conflicts.Clear();
 
            try {
                this.isInSubmitChanges = true;

                if (System.Transactions.Transaction.Current == null && this.provider.Transaction == null) { 
                    bool openedConnection = false;
                    DbTransaction transaction = null; 
                    try { 
                        if (this.provider.Connection.State == ConnectionState.Open) {
                            this.provider.ClearConnection(); 
                        }
                        if (this.provider.Connection.State == ConnectionState.Closed) {
                            this.provider.Connection.Open();
                            openedConnection = true; 
                        }
                        transaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted); 
                        this.provider.Transaction = transaction; 
                        new ChangeProcessor(this.services, this).SubmitChanges(failureMode);
                        this.AcceptChanges(); 

                        // to commit a transaction, there can be no open readers
                        // on the connection.
                        this.provider.ClearConnection(); 

                        transaction.Commit(); 
                    } 
                    catch {
                        if (transaction != null) { 
                            try {
                                transaction.Rollback();
                            }
                            catch { 
                                // squelch any addition exception
                            } 
                        } 
                        throw;
                    } 
                    finally {
                        this.provider.Transaction = null;
                        if (openedConnection) {
                            this.provider.Connection.Close(); 
                        }
                    } 
                } 
                else {
                    new ChangeProcessor(services, this).SubmitChanges(failureMode); 
                    this.AcceptChanges();
                }
            }
            finally { 
                this.isInSubmitChanges = false;
            } 
        } 

        ///  
        /// Refresh the specified object using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the
        /// database) an InvalidOperationException is thrown.
        ///  
        /// How the refresh should be performed.
        /// The object to refresh.  The object must be 
        /// the result of a previous query. 
        public void Refresh(RefreshMode mode, object entity)
        { 
            CheckDispose();
            CheckNotInSubmitChanges();
            VerifyTrackingEnabled();
            if (entity == null) 
            {
                throw Error.ArgumentNull("entity"); 
            } 
            Array items = Array.CreateInstance(entity.GetType(), 1);
            items.SetValue(entity, 0); 
            this.Refresh(mode, items as IEnumerable);
        }

        ///  
        /// Refresh a set of objects using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the 
        /// database) an InvalidOperationException is thrown. 
        /// 
        /// How the refresh should be performed. 
        /// The objects to refresh.
        public void Refresh(RefreshMode mode, params object[] entities)
        {
            CheckDispose(); // code hygeine requirement 

            if (entities == null){ 
                throw Error.ArgumentNull("entities"); 
            }
 
            Refresh(mode, (IEnumerable)entities);
        }

        ///  
        /// Refresh a collection of objects using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the 
        /// database) an InvalidOperationException is thrown. 
        /// 
        /// How the refresh should be performed. 
        /// The collection of objects to refresh.
        public void Refresh(RefreshMode mode, IEnumerable entities)
        {
            CheckDispose(); 
            CheckNotInSubmitChanges();
            VerifyTrackingEnabled(); 
 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }

            // if the collection is a query, we need to execute and buffer,
            // since below we will be issuing additional queries and can only 
            // have a single reader open.
            var list = entities.Cast().ToList(); 
 
            // create a fresh context to fetch new state from
            DataContext refreshContext = this.CreateRefreshContext(); 

            foreach (object o in list) {
                // verify that each object in the list is an entity
                MetaType inheritanceRoot = services.Model.GetMetaType(o.GetType()).InheritanceRoot; 
                GetTable(inheritanceRoot.Type);
 
                TrackedObject trackedObject = this.services.ChangeTracker.GetTrackedObject(o); 
                if (trackedObject == null) {
                    throw Error.UnrecognizedRefreshObject(); 
                }

                // query to get the current database values
                object[] keyValues = CommonDataServices.GetKeyValues(trackedObject.Type, trackedObject.Original); 
                object freshInstance = refreshContext.Services.GetObjectByKey(trackedObject.Type, keyValues);
                if (freshInstance == null) { 
                    throw Error.RefreshOfDeletedObject(); 
                }
 
                // refresh the tracked object using the new values and
                // the mode specified.
                trackedObject.Refresh(mode, freshInstance);
            } 
        }
 
        internal DataContext CreateRefreshContext() { 
            CheckDispose();
            return new DataContext(this); 
        }

        private void AcceptChanges() {
            CheckDispose(); 
            VerifyTrackingEnabled();
            this.services.ChangeTracker.AcceptChanges(); 
        } 

        ///  
        /// Returns the query text in the database server's native query language
        /// that would need to be executed to perform the specified query.
        /// 
        /// The query 
        /// 
        internal string GetQueryText(IQueryable query) { 
            CheckDispose(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            return this.provider.GetQueryText(query.Expression);
        }
 
        /// 
        /// Returns an IDbCommand object representing the query in the database server's 
        /// native query language. 
        /// 
        ///  
        /// 
        public DbCommand GetCommand(IQueryable query) {
            CheckDispose();
            if (query == null) { 
                throw Error.ArgumentNull("query");
            } 
            return this.provider.GetCommand(query.Expression); 
        }
 
        /// 
        /// Returns the command text in the database server's native query langauge
        /// that would need to be executed in order to persist the changes made to the
        /// objects back into the database. 
        /// 
        ///  
        internal string GetChangeText() { 
            CheckDispose();
            VerifyTrackingEnabled(); 
            return new ChangeProcessor(services, this).GetChangeText();
        }

        ///  
        /// Computes the un-ordered set of objects that have changed
        ///  
        ///  
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ChangeSet", Justification="The capitalization was deliberately chosen.")]
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Non-trivial operations are not suitable for properties.")] 
        public ChangeSet GetChangeSet() {
            CheckDispose();
            return new ChangeProcessor(this.services, this).GetChangeSet();
        } 

        ///  
        /// Execute a command against the database server that does not return a sequence of objects. 
        /// The command is specified using the server's native query language, such as SQL.
        ///  
        /// The command specified in the server's native query language.
        /// The parameter values to use for the query.
        /// A single integer return value
        public int ExecuteCommand(string command, params object[] parameters) { 
            CheckDispose();
            if (command == null) { 
                throw Error.ArgumentNull("command"); 
            }
            if (parameters == null) { 
                throw Error.ArgumentNull("parameters");
            }
            return (int)this.ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), command, parameters).ReturnValue;
        } 

        ///  
        /// Execute the sequence returning query against the database server. 
        /// The query is specified using the server's native query language, such as SQL.
        ///  
        /// The element type of the result sequence.
        /// The query specified in the server's native query language.
        /// The parameter values to use for the query.
        /// An IEnumerable sequence of objects. 
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        public IEnumerable ExecuteQuery(string query, params object[] parameters) { 
            CheckDispose(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            if (parameters == null) {
                throw Error.ArgumentNull("parameters");
            } 
            return (IEnumerable)this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), query, parameters).ReturnValue;
        } 
 
        /// 
        /// Execute the sequence returning query against the database server. 
        /// The query is specified using the server's native query language, such as SQL.
        /// 
        /// The element type of the result sequence.
        /// The query specified in the server's native query language. 
        /// The parameter values to use for the query.
        ///  
        public IEnumerable ExecuteQuery(Type elementType, string query, params object[] parameters) { 
            CheckDispose();
            if (elementType == null) { 
                throw Error.ArgumentNull("elementType");
            }
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            if (parameters == null) { 
                throw Error.ArgumentNull("parameters"); 
            }
            if (_miExecuteQuery == null) { 
                _miExecuteQuery = typeof(DataContext).GetMethods().Single(m => m.Name == "ExecuteQuery" && m.GetParameters().Length == 2);
            }
            return (IEnumerable)this.ExecuteMethodCall(this, _miExecuteQuery.MakeGenericMethod(elementType), query, parameters).ReturnValue;
        } 
        private static MethodInfo _miExecuteQuery;
 
 
        /// 
        /// Executes the equivalent of the specified method call on the database server. 
        /// 
        /// The instance the method is being called on.
        /// The reflection MethodInfo for the method to invoke.
        /// The parameters for the method call. 
        /// The result of the method call. Use this type's ReturnValue property to access the actual return value.
        internal protected IExecuteResult ExecuteMethodCall(object instance, MethodInfo methodInfo, params object[] parameters) { 
            CheckDispose(); 
            if (instance == null) {
                throw Error.ArgumentNull("instance"); 
            }
            if (methodInfo == null) {
                throw Error.ArgumentNull("methodInfo");
            } 
            if (parameters == null) {
                throw Error.ArgumentNull("parameters"); 
            } 
            return this.provider.Execute(this.GetMethodCall(instance, methodInfo, parameters));
        } 

        /// 
        /// Create a query object for the specified method call.
        ///  
        /// The element type of the query.
        /// The instance the method is being called on. 
        /// The reflection MethodInfo for the method to invoke. 
        /// The parameters for the method call.
        /// The returned query object 
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        internal protected IQueryable CreateMethodCallQuery(object instance, MethodInfo methodInfo, params object[] parameters) {
            CheckDispose();
            if (instance == null) { 
                throw Error.ArgumentNull("instance");
            } 
            if (methodInfo == null) { 
                throw Error.ArgumentNull("methodInfo");
            } 
            if (parameters == null) {
                throw Error.ArgumentNull("parameters");
            }
            if (!typeof(IQueryable).IsAssignableFrom(methodInfo.ReturnType)) { 
                throw Error.ExpectedQueryableArgument("methodInfo", typeof(IQueryable));
            } 
            return new DataQuery(this, this.GetMethodCall(instance, methodInfo, parameters)); 
        }
 
        private Expression GetMethodCall(object instance, MethodInfo methodInfo, params object[] parameters) {
            CheckDispose();
            if (parameters.Length > 0) {
                ParameterInfo[] pis = methodInfo.GetParameters(); 
                List args = new List(parameters.Length);
                for (int i = 0, n = parameters.Length; i < n; i++) { 
                    Type pType = pis[i].ParameterType; 
                    if (pType.IsByRef) {
                        pType = pType.GetElementType(); 
                    }
                    args.Add(Expression.Constant(parameters[i], pType));
                }
                return Expression.Call(Expression.Constant(instance), methodInfo, args); 
            }
            return Expression.Call(Expression.Constant(instance), methodInfo); 
        } 

        ///  
        /// Execute a dynamic insert
        /// 
        /// 
        internal protected void ExecuteDynamicInsert(object entity) { 
            CheckDispose();
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            this.CheckInSubmitChanges(); 
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject();
            } 
            this.services.ChangeDirector.DynamicInsert(tracked);
        } 
 
        /// 
        /// Execute a dynamic update 
        /// 
        /// 
        internal protected void ExecuteDynamicUpdate(object entity) {
            CheckDispose(); 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            this.CheckInSubmitChanges();
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject();
            }
            int result = this.services.ChangeDirector.DynamicUpdate(tracked); 
            if (result == 0) {
                throw new ChangeConflictException(); 
            } 
        }
 
        /// 
        /// Execute a dynamic delete
        /// 
        ///  
        internal protected void ExecuteDynamicDelete(object entity) {
            CheckDispose(); 
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            this.CheckInSubmitChanges();
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject(); 
            }
            int result = this.services.ChangeDirector.DynamicDelete(tracked); 
            if (result == 0) { 
                throw new ChangeConflictException();
            } 
        }

        /// 
        /// Translates the data from a DbDataReader into sequence of objects. 
        /// 
        /// The element type of the resulting sequence 
        /// The DbDataReader to translate 
        /// The translated sequence of objects
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        public IEnumerable Translate(DbDataReader reader) {
            CheckDispose();
            return (IEnumerable)this.Translate(typeof(TResult), reader);
        } 

        ///  
        /// Translates the data from a DbDataReader into sequence of objects. 
        /// 
        /// The element type of the resulting sequence 
        /// The DbDataReader to translate
        /// The translated sequence of objects
        public IEnumerable Translate(Type elementType, DbDataReader reader) {
            CheckDispose(); 
            if (elementType == null) {
                throw Error.ArgumentNull("elementType"); 
            } 
            if (reader == null) {
                throw Error.ArgumentNull("reader"); 
            }
            return this.provider.Translate(elementType, reader);
        }
 
        /// 
        /// Translates the data from a DbDataReader into IMultipleResults. 
        ///  
        /// The DbDataReader to translate
        /// The translated sequence of objects 
        public IMultipleResults Translate(DbDataReader reader) {
            CheckDispose();
            if (reader == null) {
                throw Error.ArgumentNull("reader"); 
            }
            return this.provider.Translate(reader); 
        } 

        ///  
        /// Remove all Include\Subquery LoadOptions settings.
        /// 
        internal void ResetLoadOptions() {
            CheckDispose(); 
            this.loadOptions = null;
        } 
 
        /// 
        /// The DataLoadOptions used to define prefetch behavior for defer loaded members 
        /// and membership of related collections.
        /// 
        public DataLoadOptions LoadOptions {
            get { 
                CheckDispose();
                return this.loadOptions; 
            } 
            set {
                CheckDispose(); 
                if (this.services.HasCachedObjects && value != this.loadOptions) {
                    throw Error.LoadOptionsChangeNotAllowedAfterQuery();
                }
                if (value != null) { 
                    value.Freeze();
                } 
                this.loadOptions = value; 
            }
        } 

        /// 
        /// This list of change conflicts produced by the last call to SubmitChanges.  Use this collection
        /// to resolve conflicts after catching a ChangeConflictException and before calling SubmitChanges again. 
        /// 
        public ChangeConflictCollection ChangeConflicts { 
            get { 
                CheckDispose();
                return this.conflicts; 
            }
        }
    }
 
    /// 
    /// ITable is the common interface for DataContext tables. It can be used as the source 
    /// of a dynamic/runtime-generated query. 
    /// 
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="[....]: Meant to represent a database table which is delayed loaded and doesn't provide collection semantics.")] 
    public interface ITable : IQueryable {
        /// 
        /// The DataContext containing this Table.
        ///  
        DataContext Context { get; }
        ///  
        /// Adds an entity in a 'pending insert' state to this table.  The added entity will not be observed 
        /// in query results from this table until after SubmitChanges has been called. Any untracked
        /// objects referenced directly or transitively by the entity will also be inserted. 
        /// 
        /// 
        void InsertOnSubmit(object entity);
        ///  
        /// Adds all entities of a collection to the DataContext in a 'pending insert' state.
        /// The added entities will not be observed in query results until after SubmitChanges() 
        /// has been called. Any untracked objects referenced directly or transitively by the 
        /// the inserted entities will also be inserted.
        ///  
        /// 
        void InsertAllOnSubmit(IEnumerable entities);
        /// 
        /// Attaches an entity to the DataContext in an unmodified state, similiar to as if it had been 
        /// retrieved via a query. Other entities accessible from this entity are attached as unmodified
        /// but may subsequently be transitioned to other states by performing table operations on them 
        /// individually. 
        /// 
        ///  
        void Attach(object entity);
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state.
        /// If attaching as modified, the entity must either declare a version member or must 
        /// not participate in update conflict checking. Other entities accessible from this
        /// entity are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually. 
        /// 
        ///  
        /// 
        void Attach(object entity, bool asModified);
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state by specifying both the entity 
        /// and its original state. Other entities accessible from this
        /// entity are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually. 
        /// 
        /// The entity to attach. 
        /// An instance of the same entity type with data members containing
        /// the original values.
        void Attach(object entity, object original);
        ///  
        /// Attaches all entities of a collection to the DataContext in an unmodified state,
        /// similiar to as if each had been retrieved via a query. Other entities accessible from these 
        /// entities are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually.
        ///  
        /// 
        void AttachAll(IEnumerable entities);
        /// 
        /// Attaches all entities of a collection to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking.
        /// Other entities accessible from these 
        /// entities are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually.
        ///  
        /// The collection of entities.
        /// True if the entities are to be attach as modified.
        void AttachAll(IEnumerable entities, bool asModified);
        ///  
        /// Puts an entity from this table into a 'pending delete' state.  The removed entity will not be observed
        /// missing from query results until after SubmitChanges() has been called. 
        ///  
        /// The entity to remove.
        void DeleteOnSubmit(object entity); 
        /// 
        /// Puts all entities from the collection 'entities' into a 'pending delete' state.  The removed entities will
        /// not be observed missing from the query results until after SubmitChanges() is called.
        ///  
        /// 
        void DeleteAllOnSubmit(IEnumerable entities); 
        ///  
        /// Returns an instance containing the original state of the entity.
        ///  
        /// 
        /// 
        object GetOriginalEntityState(object entity);
        ///  
        /// Returns an array of modified members containing their current and original values
        /// for the entity specified. 
        ///  
        /// 
        ///  
        ModifiedMemberInfo[] GetModifiedMembers(object entity);
        /// 
        /// True if the table is read-only.
        ///  
        bool IsReadOnly { get; }
    } 
 
    /// 
    /// Table is a collection of persistent entities. It always contains the set of entities currently 
    /// persisted in the database. Use it as a source of queries and to add/insert and remove/delete entities.
    /// 
    /// 
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="[....]: Meant to represent a database table which is delayed loaded and doesn't provide collection semantics.")] 
    public sealed class Table : IQueryable, IQueryProvider, IEnumerable, IQueryable, IEnumerable, ITable, IListSource
        where TEntity : class { 
        DataContext context; 
        MetaTable metaTable;
 
        internal Table(DataContext context, MetaTable metaTable) {
            System.Diagnostics.Debug.Assert(metaTable != null);
            this.context = context;
            this.metaTable = metaTable; 
        }
 
        ///  
        /// The DataContext containing this Table.
        ///  
        public DataContext Context {
            get { return this.context; }
        }
 
        /// 
        /// True if the table is read-only. 
        ///  
        public bool IsReadOnly {
            get { return !metaTable.RowType.IsEntity; } 
        }

        Expression IQueryable.Expression {
            get { return Expression.Constant(this); } 
        }
 
        Type IQueryable.ElementType { 
            get { return typeof(TEntity); }
        } 

        IQueryProvider IQueryable.Provider{
            get{
                return (IQueryProvider)this; 
            }
        } 
 
        IQueryable IQueryProvider.CreateQuery(Expression expression) {
            if (expression == null) { 
                throw Error.ArgumentNull("expression");
            }
            Type eType = System.Data.Linq.SqlClient.TypeSystem.GetElementType(expression.Type);
            Type qType = typeof(IQueryable<>).MakeGenericType(eType); 
            if (!qType.IsAssignableFrom(expression.Type)) {
                throw Error.ExpectedQueryableArgument("expression", qType); 
            } 
            Type dqType = typeof(DataQuery<>).MakeGenericType(eType);
            return (IQueryable)Activator.CreateInstance(dqType, new object[] { this.context, expression }); 
        }

        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        IQueryable IQueryProvider.CreateQuery(Expression expression) { 
            if (expression == null) {
                throw Error.ArgumentNull("expression"); 
            } 
            if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) {
                throw Error.ExpectedQueryableArgument("expression", typeof(IEnumerable)); 
            }
            return new DataQuery(this.context, expression);
        }
 
        object IQueryProvider.Execute(Expression expression) {
            return this.context.Provider.Execute(expression).ReturnValue; 
        } 

        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        TResult IQueryProvider.Execute(Expression expression) {
            return (TResult)this.context.Provider.Execute(expression).ReturnValue;
        }
 
        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator(); 
        } 

        IEnumerator IEnumerable.GetEnumerator() { 
            return this.GetEnumerator();
        }

        public IEnumerator GetEnumerator() { 
            return ((IEnumerable)this.context.Provider.Execute(Expression.Constant(this)).ReturnValue).GetEnumerator();
        } 
 
        bool IListSource.ContainsListCollection {
            get { return false; } 
        }

        private IBindingList cachedList;
 
        IList IListSource.GetList() {
            if (cachedList == null) { 
                cachedList = GetNewBindingList(); 
            }
            return cachedList; 
        }

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Method doesn't represent a property of the type.")]
        public IBindingList GetNewBindingList() { 
            return BindingList.Create(this.context, this);
        } 
 
        /// 
        /// Adds an entity in a 'pending insert' state to this table.  The added entity will not be observed 
        /// in query results from this table until after SubmitChanges() has been called.  Any untracked
        /// objects referenced directly or transitively by the entity will also be inserted.
        /// 
        ///  
        public void InsertOnSubmit(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled();
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) { 
                throw Error.TypeCouldNotBeAdded(type.Type);
            } 
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked == null) {
                tracked = this.context.Services.ChangeTracker.Track(entity); 
                tracked.ConvertToNew();
            } else if (tracked.IsWeaklyTracked) {
                tracked.ConvertToNew();
            } else if (tracked.IsDeleted) { 
                tracked.ConvertToPossiblyModified();
            } else if (tracked.IsRemoved) { 
                tracked.ConvertToNew(); 
            } else if (!tracked.IsNew) {
                throw Error.CantAddAlreadyExistingItem(); 
            }
        }

        void ITable.InsertOnSubmit(object entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType();
            }
            this.InsertOnSubmit(tEntity);
        } 

        ///  
        /// Adds all entities of a collection to the DataContext in a 'pending insert' state. 
        /// The added entities will not be observed in query results until after SubmitChanges()
        /// has been called. 
        /// 
        /// 
        public void InsertAllOnSubmit(IEnumerable entities) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.ToList();
            foreach (TEntity entity in list) {
                this.InsertOnSubmit(entity);
            } 
        }
 
        void ITable.InsertAllOnSubmit(IEnumerable entities) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this; 
            foreach (object entity in list) { 
                itable.InsertOnSubmit(entity);
            } 
        }

        /// 
        /// Returns true if this specific type is mapped into the database. 
        /// For example, an abstract type can't be present because it can not be instantiated.
        ///  
        private static bool IsTrackableType(MetaType type) { 
            if (type == null) {
                return false; 
            }
            if (!type.CanInstantiate) {
                return false;
            } 
            if (type.HasInheritance && !type.HasInheritanceCode) {
                return false; 
            } 
            return true;
        } 

        /// 
        /// Puts an entity from this table into a 'pending delete' state.  The removed entity will not be observed
        /// missing from query results until after SubmitChanges() has been called. 
        /// 
        ///  
        public void DeleteOnSubmit(TEntity entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked != null) { 
                if (tracked.IsNew) { 
                    tracked.ConvertToRemoved();
                } 
                else if (tracked.IsPossiblyModified || tracked.IsModified) {
                    tracked.ConvertToDeleted();
                }
            } 
            else {
                throw Error.CannotRemoveUnattachedEntity(); 
            } 
        }
 
        void ITable.DeleteOnSubmit(object entity) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType(); 
            }
            this.DeleteOnSubmit(tEntity); 
        }

        /// 
        /// Puts all entities from the collection 'entities' into a 'pending delete' state.  The removed entities will 
        /// not be observed missing from the query results until after SubmitChanges() is called.
        ///  
        ///  
        public void DeleteAllOnSubmit(IEnumerable entities) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled();
            List list = entities.ToList(); 
            foreach (TEntity entity in list) { 
                this.DeleteOnSubmit(entity);
            } 
        }

        void ITable.DeleteAllOnSubmit(IEnumerable entities) {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this;
            foreach (object entity in list) {
                itable.DeleteOnSubmit(entity); 
            }
        } 
 
        /// 
        /// Attaches an entity to the DataContext in an unmodified state, similiar to as if it had been 
        /// retrieved via a query. Deferred loading is not enabled. Other entities accessible from this
        /// entity are not automatically attached.
        /// 
        ///  
        public void Attach(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            this.Attach(entity, false); 
        }

        void ITable.Attach(object entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity; 
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType(); 
            }
            this.Attach(tEntity, false);
        }
 
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking. 
        /// Deferred loading is not enabled. Other entities accessible from this entity are not automatically attached.
        ///  
        /// 
        /// 
        public void Attach(TEntity entity, bool asModified) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) {
                throw Error.TypeCouldNotBeTracked(type.Type);
            } 
            if (asModified) {
                bool canAttach = type.VersionMember != null || !type.HasUpdateCheck; 
                if (!canAttach) { 
                    throw Error.CannotAttachAsModifiedWithoutOriginalState();
                } 
            }
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null || tracked.IsWeaklyTracked) {
                if (tracked == null) { 
                    tracked = this.context.Services.ChangeTracker.Track(entity, true);
                } 
                if (asModified) { 
                    tracked.ConvertToModified();
                } else { 
                    tracked.ConvertToUnmodified();
                }
                if (this.Context.Services.InsertLookupCachedObject(type, entity) != entity) {
                    throw new DuplicateKeyException(entity, Strings.CantAddAlreadyExistingKey); 
                }
                tracked.InitializeDeferredLoaders(); 
            } 
            else {
                throw Error.CannotAttachAlreadyExistingEntity(); 
            }
        }

        void ITable.Attach(object entity, bool asModified) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType();
            }
            this.Attach(tEntity, asModified);
        } 

        ///  
        /// Attaches an entity to the DataContext in either a modified or unmodified state by specifying both the entity 
        /// and its original state.
        ///  
        /// The entity to attach.
        /// An instance of the same entity type with data members containing
        /// the original values.
        public void Attach(TEntity entity, TEntity original) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            if (original == null) {
                throw Error.ArgumentNull("original"); 
            }
            if (entity.GetType() != original.GetType()) {
                throw Error.OriginalEntityIsWrongType();
            } 
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled(); 
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) { 
                throw Error.TypeCouldNotBeTracked(type.Type);
            }
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null || tracked.IsWeaklyTracked) { 
                if (tracked == null) {
                    tracked = this.context.Services.ChangeTracker.Track(entity, true); 
                } 
                tracked.ConvertToPossiblyModified(original);
                if (this.Context.Services.InsertLookupCachedObject(type, entity) != entity) { 
                    throw new DuplicateKeyException(entity, Strings.CantAddAlreadyExistingKey);
                }
                tracked.InitializeDeferredLoaders();
            } 
            else {
                throw Error.CannotAttachAlreadyExistingEntity(); 
            } 
        }
 
        void ITable.Attach(object entity, object original) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            if (original == null) {
                throw Error.ArgumentNull("original"); 
            } 
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled();
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType(); 
            }
            if (entity.GetType() != original.GetType()) { 
                throw Error.OriginalEntityIsWrongType(); 
            }
            this.Attach(tEntity, (TEntity)original); 
        }

        /// 
        /// Attaches all entities of a collection to the DataContext in an unmodified state, 
        /// similiar to as if each had been retrieved via a query. Deferred loading is not enabled.
        /// Other entities accessible from these entities are not automatically attached. 
        ///  
        /// 
        public void AttachAll(IEnumerable entities) where TSubEntity : TEntity { 
            if (entities == null) {
                throw Error.ArgumentNull("entities");
            }
            this.AttachAll(entities, false); 
        }
 
        void ITable.AttachAll(IEnumerable entities) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            ((ITable)this).AttachAll(entities, false);
        }
 
        /// 
        /// Attaches all entities of a collection to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking. 
        /// Deferred loading is not enabled.  Other entities accessible from these entities are not automatically attached.
        ///  
        /// The collection of entities.
        /// True if the entities are to be attach as modified.
        public void AttachAll(IEnumerable entities, bool asModified) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.ToList();
            foreach (TEntity entity in list) {
                this.Attach(entity, asModified);
            } 
        }
 
        void ITable.AttachAll(IEnumerable entities, bool asModified) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this; 
            foreach (object entity in list) { 
                itable.Attach(entity, asModified);
            } 
        }

        /// 
        /// Returns an instance containing the original state of the entity. 
        /// 
        ///  
        ///  
        public TEntity GetOriginalEntityState(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            }
            MetaType type = this.Context.Mapping.GetMetaType(entity.GetType());
            if (type == null || !type.IsEntity) { 
                throw Error.EntityIsTheWrongType();
            } 
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked != null) {
                if (tracked.Original != null) { 
                    return (TEntity) tracked.CreateDataCopy(tracked.Original);
                }
                else {
                    return (TEntity) tracked.CreateDataCopy(tracked.Current); 
                }
            } 
            return null; 
        }
 
        object ITable.GetOriginalEntityState(object entity) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType(); 
            }
            return this.GetOriginalEntityState(tEntity); 
        }

        /// 
        /// Returns an array of modified members containing their current and original values 
        /// for the entity specified.
        ///  
        ///  
        /// 
        public ModifiedMemberInfo[] GetModifiedMembers(TEntity entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            }
            MetaType type = this.Context.Mapping.GetMetaType(entity.GetType()); 
            if (type == null || !type.IsEntity) {
                throw Error.EntityIsTheWrongType(); 
            } 
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked != null) { 
                return tracked.GetModifiedMembers().ToArray();
            }
            return new ModifiedMemberInfo[] { };
        } 

        ModifiedMemberInfo[] ITable.GetModifiedMembers(object entity) { 
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType();
            } 
            return this.GetModifiedMembers(tEntity);
        } 
 
        private void CheckReadOnly() {
            if (this.IsReadOnly) { 
                throw Error.CannotPerformCUDOnReadOnlyTable(ToString());
            }
        }
 
        public override string ToString() {
            return "Table(" + typeof(TEntity).Name + ")"; 
        } 
    }
 
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ChangeSet", Justification="The capitalization was deliberately chosen.")]
    public sealed class ChangeSet {
        ReadOnlyCollection inserts;
        ReadOnlyCollection deletes; 
        ReadOnlyCollection updates;
 
        internal ChangeSet( 
            ReadOnlyCollection inserts,
            ReadOnlyCollection deletes, 
            ReadOnlyCollection updates
            ) {
            this.inserts = inserts;
            this.deletes = deletes; 
            this.updates = updates;
        } 
 
        public IList Inserts {
            get { return this.inserts; } 
        }

        public IList Deletes {
            get { return this.deletes; } 
        }
 
        public IList Updates { 
            get { return this.updates; }
        } 

        public override string ToString() {
            return "{" +
                string.Format( 
                    Globalization.CultureInfo.InvariantCulture,
                    "Inserts: {0}, Deletes: {1}, Updates: {2}", 
                    this.Inserts.Count, 
                    this.Deletes.Count,
                    this.Updates.Count 
                    ) + "}";
        }
    }
 
    [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "[....]: Types are never compared to each other.  When comparisons happen it is against the entities that are represented by these constructs.")]
    public struct ModifiedMemberInfo { 
        MemberInfo member; 
        object current;
        object original; 

        internal ModifiedMemberInfo(MemberInfo member, object current, object original) {
            this.member = member;
            this.current = current; 
            this.original = original;
        } 
 
        public MemberInfo Member {
            get { return this.member; } 
        }

        public object CurrentValue {
            get { return this.current; } 
        }
 
        public object OriginalValue { 
            get { return this.original; }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; 
using System.Configuration;
using System.Data; 
using System.Data.Common; 
using System.Globalization;
using System.IO; 
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text; 
using System.Transactions;
using System.Xml; 
 
namespace System.Data.Linq {
    using System.Data.Linq.Mapping; 
    using System.Data.Linq.Provider;
    using System.Diagnostics.CodeAnalysis;

    ///  
    /// Used to specify how a submit should behave when one
    /// or more updates fail due to optimistic concurrency 
    /// conflicts. 
    /// 
    public enum ConflictMode { 
        /// 
        /// Fail immediately when the first change conflict is encountered.
        /// 
        FailOnFirstConflict, 
        /// 
        /// Only fail after all changes have been attempted. 
        ///  
        ContinueOnConflict
    } 

    /// 
    /// Used to specify a value synchronization strategy.
    ///  
    public enum RefreshMode {
        ///  
        /// Keep the current values. 
        /// 
        KeepCurrentValues, 
        /// 
        /// Current values that have been changed are not modified, but
        /// any unchanged values are updated with the current database
        /// values.  No changes are lost in this merge. 
        /// 
        KeepChanges, 
        ///  
        /// All current values are overwritten with current database values,
        /// regardless of whether they have been changed. 
        /// 
        OverwriteCurrentValues
    }
 
    /// 
    /// The DataContext is the source of all entities mapped over a database connection. 
    /// It tracks changes made to all retrieved entities and maintains an 'identity cache' 
    /// that guarantees that entities retrieved more than once are represented using the
    /// same object instance. 
    /// 
    public class DataContext : IDisposable {
        CommonDataServices services;
        IProvider provider; 
        Dictionary tables;
        bool objectTrackingEnabled = true; 
        bool deferredLoadingEnabled = true; 
        bool disposed;
        bool isInSubmitChanges; 
        DataLoadOptions loadOptions;
        ChangeConflictCollection conflicts;

        private DataContext() { 
        }
 
        public DataContext(string fileOrServerOrConnection) { 
            if (fileOrServerOrConnection == null) {
                throw Error.ArgumentNull("fileOrServerOrConnection"); 
            }
            this.InitWithDefaultMapping(fileOrServerOrConnection);
        }
 
        public DataContext(string fileOrServerOrConnection, MappingSource mapping) {
            if (fileOrServerOrConnection == null) { 
                throw Error.ArgumentNull("fileOrServerOrConnection"); 
            }
            if (mapping == null) { 
                throw Error.ArgumentNull("mapping");
            }
            this.Init(fileOrServerOrConnection, mapping);
        } 

        public DataContext(IDbConnection connection) { 
            if (connection == null) { 
                throw Error.ArgumentNull("connection");
            } 
            this.InitWithDefaultMapping(connection);
        }

        public DataContext(IDbConnection connection, MappingSource mapping) { 
            if (connection == null) {
                throw Error.ArgumentNull("connection"); 
            } 
            if (mapping == null) {
                throw Error.ArgumentNull("mapping"); 
            }
            this.Init(connection, mapping);
        }
 
        internal DataContext(DataContext context) {
            if (context == null) { 
                throw Error.ArgumentNull("context"); 
            }
            this.Init(context.Connection, context.Mapping.MappingSource); 
            this.LoadOptions = context.LoadOptions;
            this.Transaction = context.Transaction;
            this.Log = context.Log;
            this.CommandTimeout = context.CommandTimeout; 
        }
 
        #region Dispose\Finalize 
        public void Dispose() {
            this.disposed = true; 
            Dispose(true);
        }
        // Not implementing finalizer here because there are no unmanaged resources
        // to release. See http://msdnwiki.microsoft.com/en-us/mtpswiki/12afb1ea-3a17-4a3f-a1f0-fcdb853e2359.aspx 

        // The bulk of the clean-up code is implemented in Dispose(bool) 
        protected virtual void Dispose(bool disposing) { 
            // Implemented but empty so that derived contexts can implement
            // a finalizer that potentially cleans up unmanaged resources. 
            if (disposing) {
                if (this.provider != null) {
                    this.provider.Dispose();
                    this.provider = null; 
                }
                this.services = null; 
                this.tables = null; 
                this.loadOptions = null;
            } 
        }

        internal void CheckDispose() {
            if (this.disposed) { 
                throw Error.DataContextCannotBeUsedAfterDispose();
            } 
        } 
        #endregion
 
        private void InitWithDefaultMapping(object connection) {
            this.Init(connection, new AttributeMappingSource());
        }
 
        internal object Clone() {
            CheckDispose(); 
            return Activator.CreateInstance(this.GetType(), new object[] { this.Connection, this.Mapping.MappingSource }); 
        }
 
        private void Init(object connection, MappingSource mapping) {
            MetaModel model = mapping.GetModel(this.GetType());
            this.services = new CommonDataServices(this, model);
            this.conflicts = new ChangeConflictCollection(); 

            // determine provider 
            Type providerType; 
            if (model.ProviderType != null) {
                providerType = model.ProviderType; 
            }
            else {
                throw Error.ProviderTypeNull();
            } 

            if (!typeof(IProvider).IsAssignableFrom(providerType)) { 
                throw Error.ProviderDoesNotImplementRequiredInterface(providerType, typeof(IProvider)); 
            }
 
            this.provider = (IProvider)Activator.CreateInstance(providerType);
            this.provider.Initialize(this.services, connection);

            this.tables = new Dictionary(); 
            this.InitTables(this);
        } 
 
        internal void ClearCache() {
            CheckDispose(); 
            this.services.ResetServices();
        }

        internal CommonDataServices Services { 
            get {
                CheckDispose(); 
                return this.services; 
            }
        } 

        /// 
        /// The connection object used by this DataContext when executing queries and commands.
        ///  
        public DbConnection Connection {
            get { 
                CheckDispose(); 
                return this.provider.Connection;
            } 
        }

        /// 
        /// The transaction object used by this DataContext when executing queries and commands. 
        /// 
        public DbTransaction Transaction { 
            get { 
                CheckDispose();
                return this.provider.Transaction; 
            }
            set {
                CheckDispose();
                this.provider.Transaction = value; 
            }
        } 
 
        /// 
        /// The command timeout to use when executing commands. 
        /// 
        public int CommandTimeout {
            get {
                CheckDispose(); 
                return this.provider.CommandTimeout;
            } 
            set { 
                CheckDispose();
                this.provider.CommandTimeout = value; 
            }
        }

        ///  
        /// A text writer used by this DataContext to output information such as query and commands
        /// being executed. 
        ///  
        public TextWriter Log {
            get { 
                CheckDispose();
                return this.provider.Log;
            }
            set { 
                CheckDispose();
                this.provider.Log = value; 
            } 
        }
 
        /// 
        /// True if object tracking is enabled, false otherwise.  Object tracking
        /// includes identity caching and change tracking.  If tracking is turned off,
        /// SubmitChanges and related functionality is disabled.  DeferredLoading is 
        /// also disabled when object tracking is disabled.
        ///  
        public bool ObjectTrackingEnabled { 
            get {
                CheckDispose(); 
                return objectTrackingEnabled;
            }
            set {
                CheckDispose(); 
                if (Services.HasCachedObjects) {
                    throw Error.OptionsCannotBeModifiedAfterQuery(); 
                } 
                objectTrackingEnabled = value;
                if (!objectTrackingEnabled) { 
                    deferredLoadingEnabled = false;
                }
                // force reinitialization of cache/tracking objects
                services.ResetServices(); 
            }
        } 
 
        /// 
        /// True if deferred loading is enabled, false otherwise.  With deferred 
        /// loading disabled, association members return default values and are
        /// not defer loaded.
        /// 
        public bool DeferredLoadingEnabled { 
            get {
                CheckDispose(); 
                return deferredLoadingEnabled; 
            }
            set { 
                CheckDispose();
                if (Services.HasCachedObjects) {
                    throw Error.OptionsCannotBeModifiedAfterQuery();
                } 
                // can't have tracking disabled and deferred loading enabled
                if (!ObjectTrackingEnabled && value) { 
                    throw Error.DeferredLoadingRequiresObjectTracking(); 
                }
                deferredLoadingEnabled = value; 
            }
        }

        ///  
        /// The mapping model used to describe the entities
        ///  
        public MetaModel Mapping { 
            get {
                CheckDispose(); 
                return this.services.Model;
            }
        }
 
        /// 
        /// Verify that change tracking is enabled, and throw an exception 
        /// if it is not. 
        /// 
        internal void VerifyTrackingEnabled() { 
            CheckDispose();
            if (!ObjectTrackingEnabled) {
                throw Error.ObjectTrackingRequired();
            } 
        }
 
        ///  
        /// Verify that submit changes is not occurring
        ///  
        internal void CheckNotInSubmitChanges() {
            CheckDispose();
            if (this.isInSubmitChanges) {
                throw Error.CannotPerformOperationDuringSubmitChanges(); 
            }
        } 
 
        /// 
        /// Verify that submit changes is occurring 
        /// 
        internal void CheckInSubmitChanges() {
            CheckDispose();
            if (!this.isInSubmitChanges) { 
                throw Error.CannotPerformOperationOutsideSubmitChanges();
            } 
        } 

        ///  
        /// Returns the strongly-typed Table object representing a collection of persistent entities.
        /// Use this collection as the starting point for queries.
        /// 
        /// The type of the entity objects. In case of a persistent hierarchy 
        /// the entity specified must be the base type of the hierarchy.
        ///  
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        public Table GetTable() where TEntity : class {
            CheckDispose(); 
            MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));
            if (metaTable == null) {
                throw Error.TypeIsNotMarkedAsTable(typeof(TEntity));
            } 
            ITable table = this.GetTable(metaTable);
            if (table.ElementType != typeof(TEntity)) { 
                throw Error.CouldNotGetTableForSubtype(typeof(TEntity), metaTable.RowType.Type); 
            }
            return (Table)table; 
        }

        /// 
        /// Returns the weakly-typed ITable object representing a collection of persistent entities. 
        /// Use this collection as the starting point for dynamic/runtime-computed queries.
        ///  
        /// The type of the entity objects. In case of a persistent hierarchy 
        /// the entity specified must be the base type of the hierarchy.
        ///  
        public ITable GetTable(Type type) {
            CheckDispose();
            if (type == null) {
                throw Error.ArgumentNull("type"); 
            }
            MetaTable metaTable = this.services.Model.GetTable(type); 
            if (metaTable == null) { 
                throw Error.TypeIsNotMarkedAsTable(type);
            } 
            if (metaTable.RowType.Type != type) {
                throw Error.CouldNotGetTableForSubtype(type, metaTable.RowType.Type);
            }
            return this.GetTable(metaTable); 
        }
 
        private ITable GetTable(MetaTable metaTable) { 
            System.Diagnostics.Debug.Assert(metaTable != null);
            ITable tb; 
            if (!this.tables.TryGetValue(metaTable, out tb)) {
                ValidateTable(metaTable);
                Type tbType = typeof(Table<>).MakeGenericType(metaTable.RowType.Type);
                tb = (ITable)Activator.CreateInstance(tbType, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, new object[] { this, metaTable }, null); 
                this.tables.Add(metaTable, tb);
            } 
            return tb; 
        }
 
        private static void ValidateTable(MetaTable metaTable) {
            // Associations can only be between entities - verify both that both ends of all
            // associations are entities.
            foreach(MetaAssociation assoc in metaTable.RowType.Associations) { 
                if(!assoc.ThisMember.DeclaringType.IsEntity) {
                    throw Error.NonEntityAssociationMapping(assoc.ThisMember.DeclaringType.Type, assoc.ThisMember.Name, assoc.ThisMember.DeclaringType.Type); 
                } 
                if(!assoc.OtherType.IsEntity) {
                    throw Error.NonEntityAssociationMapping(assoc.ThisMember.DeclaringType.Type, assoc.ThisMember.Name, assoc.OtherType.Type); 
                }
            }
        }
 
        private void InitTables(object schema) {
            FieldInfo[] fields = schema.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); 
            foreach (FieldInfo fi in fields) { 
                Type ft = fi.FieldType;
                if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) { 
                    ITable tb = (ITable)fi.GetValue(schema);
                    if (tb == null) {
                        Type rowType = ft.GetGenericArguments()[0];
                        tb = this.GetTable(rowType); 
                        fi.SetValue(schema, tb);
                    } 
                } 
            }
        } 

        /// 
        /// Internal method that can be accessed by tests to retrieve the provider
        /// The IProvider result can then be cast to the actual provider to call debug methods like 
        ///   CheckQueries, QueryCount, EnableCacheLookup
        ///  
        internal IProvider Provider { 
            get {
                CheckDispose(); 
                return this.provider;
            }
        }
 
        /// 
        /// Returns true if the database specified by the connection object exists. 
        ///  
        /// 
        public bool DatabaseExists() { 
            CheckDispose();
            return this.provider.DatabaseExists();
        }
 
        /// 
        /// Creates a new database instance (catalog or file) at the location specified by the connection 
        /// using the metadata encoded within the entities or mapping file. 
        /// 
        public void CreateDatabase() { 
            CheckDispose();
            this.provider.CreateDatabase();
        }
 
        /// 
        /// Deletes the database instance at the location specified by the connection. 
        ///  
        public void DeleteDatabase() {
            CheckDispose(); 
            this.provider.DeleteDatabase();
        }

        ///  
        /// Submits one or more commands to the database reflecting the changes made to the retreived entities.
        /// If a transaction is not already specified one will be created for the duration of this operation. 
        /// If a change conflict is encountered a ChangeConflictException will be thrown. 
        /// 
        public void SubmitChanges() { 
            CheckDispose();
            SubmitChanges(ConflictMode.FailOnFirstConflict);
        }
 
        /// 
        /// Submits one or more commands to the database reflecting the changes made to the retreived entities. 
        /// If a transaction is not already specified one will be created for the duration of this operation. 
        /// If a change conflict is encountered a ChangeConflictException will be thrown.
        /// You can override this method to implement common conflict resolution behaviors. 
        /// 
        /// Determines how SubmitChanges handles conflicts.
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "[....]: In the middle of attempting to rollback a transaction, outer transaction is thrown.")]
        public virtual void SubmitChanges(ConflictMode failureMode) { 
            CheckDispose();
            CheckNotInSubmitChanges(); 
            VerifyTrackingEnabled(); 
            this.conflicts.Clear();
 
            try {
                this.isInSubmitChanges = true;

                if (System.Transactions.Transaction.Current == null && this.provider.Transaction == null) { 
                    bool openedConnection = false;
                    DbTransaction transaction = null; 
                    try { 
                        if (this.provider.Connection.State == ConnectionState.Open) {
                            this.provider.ClearConnection(); 
                        }
                        if (this.provider.Connection.State == ConnectionState.Closed) {
                            this.provider.Connection.Open();
                            openedConnection = true; 
                        }
                        transaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted); 
                        this.provider.Transaction = transaction; 
                        new ChangeProcessor(this.services, this).SubmitChanges(failureMode);
                        this.AcceptChanges(); 

                        // to commit a transaction, there can be no open readers
                        // on the connection.
                        this.provider.ClearConnection(); 

                        transaction.Commit(); 
                    } 
                    catch {
                        if (transaction != null) { 
                            try {
                                transaction.Rollback();
                            }
                            catch { 
                                // squelch any addition exception
                            } 
                        } 
                        throw;
                    } 
                    finally {
                        this.provider.Transaction = null;
                        if (openedConnection) {
                            this.provider.Connection.Close(); 
                        }
                    } 
                } 
                else {
                    new ChangeProcessor(services, this).SubmitChanges(failureMode); 
                    this.AcceptChanges();
                }
            }
            finally { 
                this.isInSubmitChanges = false;
            } 
        } 

        ///  
        /// Refresh the specified object using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the
        /// database) an InvalidOperationException is thrown.
        ///  
        /// How the refresh should be performed.
        /// The object to refresh.  The object must be 
        /// the result of a previous query. 
        public void Refresh(RefreshMode mode, object entity)
        { 
            CheckDispose();
            CheckNotInSubmitChanges();
            VerifyTrackingEnabled();
            if (entity == null) 
            {
                throw Error.ArgumentNull("entity"); 
            } 
            Array items = Array.CreateInstance(entity.GetType(), 1);
            items.SetValue(entity, 0); 
            this.Refresh(mode, items as IEnumerable);
        }

        ///  
        /// Refresh a set of objects using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the 
        /// database) an InvalidOperationException is thrown. 
        /// 
        /// How the refresh should be performed. 
        /// The objects to refresh.
        public void Refresh(RefreshMode mode, params object[] entities)
        {
            CheckDispose(); // code hygeine requirement 

            if (entities == null){ 
                throw Error.ArgumentNull("entities"); 
            }
 
            Refresh(mode, (IEnumerable)entities);
        }

        ///  
        /// Refresh a collection of objects using the mode specified.  If the refresh
        /// cannot be performed (for example if the object no longer exists in the 
        /// database) an InvalidOperationException is thrown. 
        /// 
        /// How the refresh should be performed. 
        /// The collection of objects to refresh.
        public void Refresh(RefreshMode mode, IEnumerable entities)
        {
            CheckDispose(); 
            CheckNotInSubmitChanges();
            VerifyTrackingEnabled(); 
 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }

            // if the collection is a query, we need to execute and buffer,
            // since below we will be issuing additional queries and can only 
            // have a single reader open.
            var list = entities.Cast().ToList(); 
 
            // create a fresh context to fetch new state from
            DataContext refreshContext = this.CreateRefreshContext(); 

            foreach (object o in list) {
                // verify that each object in the list is an entity
                MetaType inheritanceRoot = services.Model.GetMetaType(o.GetType()).InheritanceRoot; 
                GetTable(inheritanceRoot.Type);
 
                TrackedObject trackedObject = this.services.ChangeTracker.GetTrackedObject(o); 
                if (trackedObject == null) {
                    throw Error.UnrecognizedRefreshObject(); 
                }

                // query to get the current database values
                object[] keyValues = CommonDataServices.GetKeyValues(trackedObject.Type, trackedObject.Original); 
                object freshInstance = refreshContext.Services.GetObjectByKey(trackedObject.Type, keyValues);
                if (freshInstance == null) { 
                    throw Error.RefreshOfDeletedObject(); 
                }
 
                // refresh the tracked object using the new values and
                // the mode specified.
                trackedObject.Refresh(mode, freshInstance);
            } 
        }
 
        internal DataContext CreateRefreshContext() { 
            CheckDispose();
            return new DataContext(this); 
        }

        private void AcceptChanges() {
            CheckDispose(); 
            VerifyTrackingEnabled();
            this.services.ChangeTracker.AcceptChanges(); 
        } 

        ///  
        /// Returns the query text in the database server's native query language
        /// that would need to be executed to perform the specified query.
        /// 
        /// The query 
        /// 
        internal string GetQueryText(IQueryable query) { 
            CheckDispose(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            return this.provider.GetQueryText(query.Expression);
        }
 
        /// 
        /// Returns an IDbCommand object representing the query in the database server's 
        /// native query language. 
        /// 
        ///  
        /// 
        public DbCommand GetCommand(IQueryable query) {
            CheckDispose();
            if (query == null) { 
                throw Error.ArgumentNull("query");
            } 
            return this.provider.GetCommand(query.Expression); 
        }
 
        /// 
        /// Returns the command text in the database server's native query langauge
        /// that would need to be executed in order to persist the changes made to the
        /// objects back into the database. 
        /// 
        ///  
        internal string GetChangeText() { 
            CheckDispose();
            VerifyTrackingEnabled(); 
            return new ChangeProcessor(services, this).GetChangeText();
        }

        ///  
        /// Computes the un-ordered set of objects that have changed
        ///  
        ///  
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ChangeSet", Justification="The capitalization was deliberately chosen.")]
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Non-trivial operations are not suitable for properties.")] 
        public ChangeSet GetChangeSet() {
            CheckDispose();
            return new ChangeProcessor(this.services, this).GetChangeSet();
        } 

        ///  
        /// Execute a command against the database server that does not return a sequence of objects. 
        /// The command is specified using the server's native query language, such as SQL.
        ///  
        /// The command specified in the server's native query language.
        /// The parameter values to use for the query.
        /// A single integer return value
        public int ExecuteCommand(string command, params object[] parameters) { 
            CheckDispose();
            if (command == null) { 
                throw Error.ArgumentNull("command"); 
            }
            if (parameters == null) { 
                throw Error.ArgumentNull("parameters");
            }
            return (int)this.ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), command, parameters).ReturnValue;
        } 

        ///  
        /// Execute the sequence returning query against the database server. 
        /// The query is specified using the server's native query language, such as SQL.
        ///  
        /// The element type of the result sequence.
        /// The query specified in the server's native query language.
        /// The parameter values to use for the query.
        /// An IEnumerable sequence of objects. 
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        public IEnumerable ExecuteQuery(string query, params object[] parameters) { 
            CheckDispose(); 
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            if (parameters == null) {
                throw Error.ArgumentNull("parameters");
            } 
            return (IEnumerable)this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), query, parameters).ReturnValue;
        } 
 
        /// 
        /// Execute the sequence returning query against the database server. 
        /// The query is specified using the server's native query language, such as SQL.
        /// 
        /// The element type of the result sequence.
        /// The query specified in the server's native query language. 
        /// The parameter values to use for the query.
        ///  
        public IEnumerable ExecuteQuery(Type elementType, string query, params object[] parameters) { 
            CheckDispose();
            if (elementType == null) { 
                throw Error.ArgumentNull("elementType");
            }
            if (query == null) {
                throw Error.ArgumentNull("query"); 
            }
            if (parameters == null) { 
                throw Error.ArgumentNull("parameters"); 
            }
            if (_miExecuteQuery == null) { 
                _miExecuteQuery = typeof(DataContext).GetMethods().Single(m => m.Name == "ExecuteQuery" && m.GetParameters().Length == 2);
            }
            return (IEnumerable)this.ExecuteMethodCall(this, _miExecuteQuery.MakeGenericMethod(elementType), query, parameters).ReturnValue;
        } 
        private static MethodInfo _miExecuteQuery;
 
 
        /// 
        /// Executes the equivalent of the specified method call on the database server. 
        /// 
        /// The instance the method is being called on.
        /// The reflection MethodInfo for the method to invoke.
        /// The parameters for the method call. 
        /// The result of the method call. Use this type's ReturnValue property to access the actual return value.
        internal protected IExecuteResult ExecuteMethodCall(object instance, MethodInfo methodInfo, params object[] parameters) { 
            CheckDispose(); 
            if (instance == null) {
                throw Error.ArgumentNull("instance"); 
            }
            if (methodInfo == null) {
                throw Error.ArgumentNull("methodInfo");
            } 
            if (parameters == null) {
                throw Error.ArgumentNull("parameters"); 
            } 
            return this.provider.Execute(this.GetMethodCall(instance, methodInfo, parameters));
        } 

        /// 
        /// Create a query object for the specified method call.
        ///  
        /// The element type of the query.
        /// The instance the method is being called on. 
        /// The reflection MethodInfo for the method to invoke. 
        /// The parameters for the method call.
        /// The returned query object 
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        internal protected IQueryable CreateMethodCallQuery(object instance, MethodInfo methodInfo, params object[] parameters) {
            CheckDispose();
            if (instance == null) { 
                throw Error.ArgumentNull("instance");
            } 
            if (methodInfo == null) { 
                throw Error.ArgumentNull("methodInfo");
            } 
            if (parameters == null) {
                throw Error.ArgumentNull("parameters");
            }
            if (!typeof(IQueryable).IsAssignableFrom(methodInfo.ReturnType)) { 
                throw Error.ExpectedQueryableArgument("methodInfo", typeof(IQueryable));
            } 
            return new DataQuery(this, this.GetMethodCall(instance, methodInfo, parameters)); 
        }
 
        private Expression GetMethodCall(object instance, MethodInfo methodInfo, params object[] parameters) {
            CheckDispose();
            if (parameters.Length > 0) {
                ParameterInfo[] pis = methodInfo.GetParameters(); 
                List args = new List(parameters.Length);
                for (int i = 0, n = parameters.Length; i < n; i++) { 
                    Type pType = pis[i].ParameterType; 
                    if (pType.IsByRef) {
                        pType = pType.GetElementType(); 
                    }
                    args.Add(Expression.Constant(parameters[i], pType));
                }
                return Expression.Call(Expression.Constant(instance), methodInfo, args); 
            }
            return Expression.Call(Expression.Constant(instance), methodInfo); 
        } 

        ///  
        /// Execute a dynamic insert
        /// 
        /// 
        internal protected void ExecuteDynamicInsert(object entity) { 
            CheckDispose();
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            this.CheckInSubmitChanges(); 
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject();
            } 
            this.services.ChangeDirector.DynamicInsert(tracked);
        } 
 
        /// 
        /// Execute a dynamic update 
        /// 
        /// 
        internal protected void ExecuteDynamicUpdate(object entity) {
            CheckDispose(); 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            this.CheckInSubmitChanges();
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject();
            }
            int result = this.services.ChangeDirector.DynamicUpdate(tracked); 
            if (result == 0) {
                throw new ChangeConflictException(); 
            } 
        }
 
        /// 
        /// Execute a dynamic delete
        /// 
        ///  
        internal protected void ExecuteDynamicDelete(object entity) {
            CheckDispose(); 
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            this.CheckInSubmitChanges();
            TrackedObject tracked = this.services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null) {
                throw Error.CannotPerformOperationForUntrackedObject(); 
            }
            int result = this.services.ChangeDirector.DynamicDelete(tracked); 
            if (result == 0) { 
                throw new ChangeConflictException();
            } 
        }

        /// 
        /// Translates the data from a DbDataReader into sequence of objects. 
        /// 
        /// The element type of the resulting sequence 
        /// The DbDataReader to translate 
        /// The translated sequence of objects
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        public IEnumerable Translate(DbDataReader reader) {
            CheckDispose();
            return (IEnumerable)this.Translate(typeof(TResult), reader);
        } 

        ///  
        /// Translates the data from a DbDataReader into sequence of objects. 
        /// 
        /// The element type of the resulting sequence 
        /// The DbDataReader to translate
        /// The translated sequence of objects
        public IEnumerable Translate(Type elementType, DbDataReader reader) {
            CheckDispose(); 
            if (elementType == null) {
                throw Error.ArgumentNull("elementType"); 
            } 
            if (reader == null) {
                throw Error.ArgumentNull("reader"); 
            }
            return this.provider.Translate(elementType, reader);
        }
 
        /// 
        /// Translates the data from a DbDataReader into IMultipleResults. 
        ///  
        /// The DbDataReader to translate
        /// The translated sequence of objects 
        public IMultipleResults Translate(DbDataReader reader) {
            CheckDispose();
            if (reader == null) {
                throw Error.ArgumentNull("reader"); 
            }
            return this.provider.Translate(reader); 
        } 

        ///  
        /// Remove all Include\Subquery LoadOptions settings.
        /// 
        internal void ResetLoadOptions() {
            CheckDispose(); 
            this.loadOptions = null;
        } 
 
        /// 
        /// The DataLoadOptions used to define prefetch behavior for defer loaded members 
        /// and membership of related collections.
        /// 
        public DataLoadOptions LoadOptions {
            get { 
                CheckDispose();
                return this.loadOptions; 
            } 
            set {
                CheckDispose(); 
                if (this.services.HasCachedObjects && value != this.loadOptions) {
                    throw Error.LoadOptionsChangeNotAllowedAfterQuery();
                }
                if (value != null) { 
                    value.Freeze();
                } 
                this.loadOptions = value; 
            }
        } 

        /// 
        /// This list of change conflicts produced by the last call to SubmitChanges.  Use this collection
        /// to resolve conflicts after catching a ChangeConflictException and before calling SubmitChanges again. 
        /// 
        public ChangeConflictCollection ChangeConflicts { 
            get { 
                CheckDispose();
                return this.conflicts; 
            }
        }
    }
 
    /// 
    /// ITable is the common interface for DataContext tables. It can be used as the source 
    /// of a dynamic/runtime-generated query. 
    /// 
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="[....]: Meant to represent a database table which is delayed loaded and doesn't provide collection semantics.")] 
    public interface ITable : IQueryable {
        /// 
        /// The DataContext containing this Table.
        ///  
        DataContext Context { get; }
        ///  
        /// Adds an entity in a 'pending insert' state to this table.  The added entity will not be observed 
        /// in query results from this table until after SubmitChanges has been called. Any untracked
        /// objects referenced directly or transitively by the entity will also be inserted. 
        /// 
        /// 
        void InsertOnSubmit(object entity);
        ///  
        /// Adds all entities of a collection to the DataContext in a 'pending insert' state.
        /// The added entities will not be observed in query results until after SubmitChanges() 
        /// has been called. Any untracked objects referenced directly or transitively by the 
        /// the inserted entities will also be inserted.
        ///  
        /// 
        void InsertAllOnSubmit(IEnumerable entities);
        /// 
        /// Attaches an entity to the DataContext in an unmodified state, similiar to as if it had been 
        /// retrieved via a query. Other entities accessible from this entity are attached as unmodified
        /// but may subsequently be transitioned to other states by performing table operations on them 
        /// individually. 
        /// 
        ///  
        void Attach(object entity);
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state.
        /// If attaching as modified, the entity must either declare a version member or must 
        /// not participate in update conflict checking. Other entities accessible from this
        /// entity are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually. 
        /// 
        ///  
        /// 
        void Attach(object entity, bool asModified);
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state by specifying both the entity 
        /// and its original state. Other entities accessible from this
        /// entity are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually. 
        /// 
        /// The entity to attach. 
        /// An instance of the same entity type with data members containing
        /// the original values.
        void Attach(object entity, object original);
        ///  
        /// Attaches all entities of a collection to the DataContext in an unmodified state,
        /// similiar to as if each had been retrieved via a query. Other entities accessible from these 
        /// entities are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually.
        ///  
        /// 
        void AttachAll(IEnumerable entities);
        /// 
        /// Attaches all entities of a collection to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking.
        /// Other entities accessible from these 
        /// entities are attached as unmodified but may subsequently be transitioned to other 
        /// states by performing table operations on them individually.
        ///  
        /// The collection of entities.
        /// True if the entities are to be attach as modified.
        void AttachAll(IEnumerable entities, bool asModified);
        ///  
        /// Puts an entity from this table into a 'pending delete' state.  The removed entity will not be observed
        /// missing from query results until after SubmitChanges() has been called. 
        ///  
        /// The entity to remove.
        void DeleteOnSubmit(object entity); 
        /// 
        /// Puts all entities from the collection 'entities' into a 'pending delete' state.  The removed entities will
        /// not be observed missing from the query results until after SubmitChanges() is called.
        ///  
        /// 
        void DeleteAllOnSubmit(IEnumerable entities); 
        ///  
        /// Returns an instance containing the original state of the entity.
        ///  
        /// 
        /// 
        object GetOriginalEntityState(object entity);
        ///  
        /// Returns an array of modified members containing their current and original values
        /// for the entity specified. 
        ///  
        /// 
        ///  
        ModifiedMemberInfo[] GetModifiedMembers(object entity);
        /// 
        /// True if the table is read-only.
        ///  
        bool IsReadOnly { get; }
    } 
 
    /// 
    /// Table is a collection of persistent entities. It always contains the set of entities currently 
    /// persisted in the database. Use it as a source of queries and to add/insert and remove/delete entities.
    /// 
    /// 
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="[....]: Meant to represent a database table which is delayed loaded and doesn't provide collection semantics.")] 
    public sealed class Table : IQueryable, IQueryProvider, IEnumerable, IQueryable, IEnumerable, ITable, IListSource
        where TEntity : class { 
        DataContext context; 
        MetaTable metaTable;
 
        internal Table(DataContext context, MetaTable metaTable) {
            System.Diagnostics.Debug.Assert(metaTable != null);
            this.context = context;
            this.metaTable = metaTable; 
        }
 
        ///  
        /// The DataContext containing this Table.
        ///  
        public DataContext Context {
            get { return this.context; }
        }
 
        /// 
        /// True if the table is read-only. 
        ///  
        public bool IsReadOnly {
            get { return !metaTable.RowType.IsEntity; } 
        }

        Expression IQueryable.Expression {
            get { return Expression.Constant(this); } 
        }
 
        Type IQueryable.ElementType { 
            get { return typeof(TEntity); }
        } 

        IQueryProvider IQueryable.Provider{
            get{
                return (IQueryProvider)this; 
            }
        } 
 
        IQueryable IQueryProvider.CreateQuery(Expression expression) {
            if (expression == null) { 
                throw Error.ArgumentNull("expression");
            }
            Type eType = System.Data.Linq.SqlClient.TypeSystem.GetElementType(expression.Type);
            Type qType = typeof(IQueryable<>).MakeGenericType(eType); 
            if (!qType.IsAssignableFrom(expression.Type)) {
                throw Error.ExpectedQueryableArgument("expression", qType); 
            } 
            Type dqType = typeof(DataQuery<>).MakeGenericType(eType);
            return (IQueryable)Activator.CreateInstance(dqType, new object[] { this.context, expression }); 
        }

        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
        IQueryable IQueryProvider.CreateQuery(Expression expression) { 
            if (expression == null) {
                throw Error.ArgumentNull("expression"); 
            } 
            if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) {
                throw Error.ExpectedQueryableArgument("expression", typeof(IEnumerable)); 
            }
            return new DataQuery(this.context, expression);
        }
 
        object IQueryProvider.Execute(Expression expression) {
            return this.context.Provider.Execute(expression).ReturnValue; 
        } 

        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")] 
        TResult IQueryProvider.Execute(Expression expression) {
            return (TResult)this.context.Provider.Execute(expression).ReturnValue;
        }
 
        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator(); 
        } 

        IEnumerator IEnumerable.GetEnumerator() { 
            return this.GetEnumerator();
        }

        public IEnumerator GetEnumerator() { 
            return ((IEnumerable)this.context.Provider.Execute(Expression.Constant(this)).ReturnValue).GetEnumerator();
        } 
 
        bool IListSource.ContainsListCollection {
            get { return false; } 
        }

        private IBindingList cachedList;
 
        IList IListSource.GetList() {
            if (cachedList == null) { 
                cachedList = GetNewBindingList(); 
            }
            return cachedList; 
        }

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Method doesn't represent a property of the type.")]
        public IBindingList GetNewBindingList() { 
            return BindingList.Create(this.context, this);
        } 
 
        /// 
        /// Adds an entity in a 'pending insert' state to this table.  The added entity will not be observed 
        /// in query results from this table until after SubmitChanges() has been called.  Any untracked
        /// objects referenced directly or transitively by the entity will also be inserted.
        /// 
        ///  
        public void InsertOnSubmit(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled();
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) { 
                throw Error.TypeCouldNotBeAdded(type.Type);
            } 
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked == null) {
                tracked = this.context.Services.ChangeTracker.Track(entity); 
                tracked.ConvertToNew();
            } else if (tracked.IsWeaklyTracked) {
                tracked.ConvertToNew();
            } else if (tracked.IsDeleted) { 
                tracked.ConvertToPossiblyModified();
            } else if (tracked.IsRemoved) { 
                tracked.ConvertToNew(); 
            } else if (!tracked.IsNew) {
                throw Error.CantAddAlreadyExistingItem(); 
            }
        }

        void ITable.InsertOnSubmit(object entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType();
            }
            this.InsertOnSubmit(tEntity);
        } 

        ///  
        /// Adds all entities of a collection to the DataContext in a 'pending insert' state. 
        /// The added entities will not be observed in query results until after SubmitChanges()
        /// has been called. 
        /// 
        /// 
        public void InsertAllOnSubmit(IEnumerable entities) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.ToList();
            foreach (TEntity entity in list) {
                this.InsertOnSubmit(entity);
            } 
        }
 
        void ITable.InsertAllOnSubmit(IEnumerable entities) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this; 
            foreach (object entity in list) { 
                itable.InsertOnSubmit(entity);
            } 
        }

        /// 
        /// Returns true if this specific type is mapped into the database. 
        /// For example, an abstract type can't be present because it can not be instantiated.
        ///  
        private static bool IsTrackableType(MetaType type) { 
            if (type == null) {
                return false; 
            }
            if (!type.CanInstantiate) {
                return false;
            } 
            if (type.HasInheritance && !type.HasInheritanceCode) {
                return false; 
            } 
            return true;
        } 

        /// 
        /// Puts an entity from this table into a 'pending delete' state.  The removed entity will not be observed
        /// missing from query results until after SubmitChanges() has been called. 
        /// 
        ///  
        public void DeleteOnSubmit(TEntity entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked != null) { 
                if (tracked.IsNew) { 
                    tracked.ConvertToRemoved();
                } 
                else if (tracked.IsPossiblyModified || tracked.IsModified) {
                    tracked.ConvertToDeleted();
                }
            } 
            else {
                throw Error.CannotRemoveUnattachedEntity(); 
            } 
        }
 
        void ITable.DeleteOnSubmit(object entity) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType(); 
            }
            this.DeleteOnSubmit(tEntity); 
        }

        /// 
        /// Puts all entities from the collection 'entities' into a 'pending delete' state.  The removed entities will 
        /// not be observed missing from the query results until after SubmitChanges() is called.
        ///  
        ///  
        public void DeleteAllOnSubmit(IEnumerable entities) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled();
            List list = entities.ToList(); 
            foreach (TEntity entity in list) { 
                this.DeleteOnSubmit(entity);
            } 
        }

        void ITable.DeleteAllOnSubmit(IEnumerable entities) {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this;
            foreach (object entity in list) {
                itable.DeleteOnSubmit(entity); 
            }
        } 
 
        /// 
        /// Attaches an entity to the DataContext in an unmodified state, similiar to as if it had been 
        /// retrieved via a query. Deferred loading is not enabled. Other entities accessible from this
        /// entity are not automatically attached.
        /// 
        ///  
        public void Attach(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity"); 
            }
            this.Attach(entity, false); 
        }

        void ITable.Attach(object entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity; 
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType(); 
            }
            this.Attach(tEntity, false);
        }
 
        /// 
        /// Attaches an entity to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking. 
        /// Deferred loading is not enabled. Other entities accessible from this entity are not automatically attached.
        ///  
        /// 
        /// 
        public void Attach(TEntity entity, bool asModified) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) {
                throw Error.TypeCouldNotBeTracked(type.Type);
            } 
            if (asModified) {
                bool canAttach = type.VersionMember != null || !type.HasUpdateCheck; 
                if (!canAttach) { 
                    throw Error.CannotAttachAsModifiedWithoutOriginalState();
                } 
            }
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null || tracked.IsWeaklyTracked) {
                if (tracked == null) { 
                    tracked = this.context.Services.ChangeTracker.Track(entity, true);
                } 
                if (asModified) { 
                    tracked.ConvertToModified();
                } else { 
                    tracked.ConvertToUnmodified();
                }
                if (this.Context.Services.InsertLookupCachedObject(type, entity) != entity) {
                    throw new DuplicateKeyException(entity, Strings.CantAddAlreadyExistingKey); 
                }
                tracked.InitializeDeferredLoaders(); 
            } 
            else {
                throw Error.CannotAttachAlreadyExistingEntity(); 
            }
        }

        void ITable.Attach(object entity, bool asModified) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType();
            }
            this.Attach(tEntity, asModified);
        } 

        ///  
        /// Attaches an entity to the DataContext in either a modified or unmodified state by specifying both the entity 
        /// and its original state.
        ///  
        /// The entity to attach.
        /// An instance of the same entity type with data members containing
        /// the original values.
        public void Attach(TEntity entity, TEntity original) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity"); 
            } 
            if (original == null) {
                throw Error.ArgumentNull("original"); 
            }
            if (entity.GetType() != original.GetType()) {
                throw Error.OriginalEntityIsWrongType();
            } 
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled(); 
            MetaType type = this.metaTable.RowType.GetInheritanceType(entity.GetType());
            if (!IsTrackableType(type)) { 
                throw Error.TypeCouldNotBeTracked(type.Type);
            }
            TrackedObject tracked = this.context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked == null || tracked.IsWeaklyTracked) { 
                if (tracked == null) {
                    tracked = this.context.Services.ChangeTracker.Track(entity, true); 
                } 
                tracked.ConvertToPossiblyModified(original);
                if (this.Context.Services.InsertLookupCachedObject(type, entity) != entity) { 
                    throw new DuplicateKeyException(entity, Strings.CantAddAlreadyExistingKey);
                }
                tracked.InitializeDeferredLoaders();
            } 
            else {
                throw Error.CannotAttachAlreadyExistingEntity(); 
            } 
        }
 
        void ITable.Attach(object entity, object original) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            if (original == null) {
                throw Error.ArgumentNull("original"); 
            } 
            CheckReadOnly();
            context.CheckNotInSubmitChanges(); 
            context.VerifyTrackingEnabled();
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType(); 
            }
            if (entity.GetType() != original.GetType()) { 
                throw Error.OriginalEntityIsWrongType(); 
            }
            this.Attach(tEntity, (TEntity)original); 
        }

        /// 
        /// Attaches all entities of a collection to the DataContext in an unmodified state, 
        /// similiar to as if each had been retrieved via a query. Deferred loading is not enabled.
        /// Other entities accessible from these entities are not automatically attached. 
        ///  
        /// 
        public void AttachAll(IEnumerable entities) where TSubEntity : TEntity { 
            if (entities == null) {
                throw Error.ArgumentNull("entities");
            }
            this.AttachAll(entities, false); 
        }
 
        void ITable.AttachAll(IEnumerable entities) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            ((ITable)this).AttachAll(entities, false);
        }
 
        /// 
        /// Attaches all entities of a collection to the DataContext in either a modified or unmodified state. 
        /// If attaching as modified, the entity must either declare a version member or must not participate in update conflict checking. 
        /// Deferred loading is not enabled.  Other entities accessible from these entities are not automatically attached.
        ///  
        /// The collection of entities.
        /// True if the entities are to be attach as modified.
        public void AttachAll(IEnumerable entities, bool asModified) where TSubEntity : TEntity {
            if (entities == null) { 
                throw Error.ArgumentNull("entities");
            } 
            CheckReadOnly(); 
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.ToList();
            foreach (TEntity entity in list) {
                this.Attach(entity, asModified);
            } 
        }
 
        void ITable.AttachAll(IEnumerable entities, bool asModified) { 
            if (entities == null) {
                throw Error.ArgumentNull("entities"); 
            }
            CheckReadOnly();
            context.CheckNotInSubmitChanges();
            context.VerifyTrackingEnabled(); 
            List list = entities.Cast().ToList();
            ITable itable = this; 
            foreach (object entity in list) { 
                itable.Attach(entity, asModified);
            } 
        }

        /// 
        /// Returns an instance containing the original state of the entity. 
        /// 
        ///  
        ///  
        public TEntity GetOriginalEntityState(TEntity entity) {
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            }
            MetaType type = this.Context.Mapping.GetMetaType(entity.GetType());
            if (type == null || !type.IsEntity) { 
                throw Error.EntityIsTheWrongType();
            } 
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity); 
            if (tracked != null) {
                if (tracked.Original != null) { 
                    return (TEntity) tracked.CreateDataCopy(tracked.Original);
                }
                else {
                    return (TEntity) tracked.CreateDataCopy(tracked.Current); 
                }
            } 
            return null; 
        }
 
        object ITable.GetOriginalEntityState(object entity) {
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) { 
                throw Error.EntityIsTheWrongType(); 
            }
            return this.GetOriginalEntityState(tEntity); 
        }

        /// 
        /// Returns an array of modified members containing their current and original values 
        /// for the entity specified.
        ///  
        ///  
        /// 
        public ModifiedMemberInfo[] GetModifiedMembers(TEntity entity) { 
            if (entity == null) {
                throw Error.ArgumentNull("entity");
            }
            MetaType type = this.Context.Mapping.GetMetaType(entity.GetType()); 
            if (type == null || !type.IsEntity) {
                throw Error.EntityIsTheWrongType(); 
            } 
            TrackedObject tracked = this.Context.Services.ChangeTracker.GetTrackedObject(entity);
            if (tracked != null) { 
                return tracked.GetModifiedMembers().ToArray();
            }
            return new ModifiedMemberInfo[] { };
        } 

        ModifiedMemberInfo[] ITable.GetModifiedMembers(object entity) { 
            if (entity == null) { 
                throw Error.ArgumentNull("entity");
            } 
            TEntity tEntity = entity as TEntity;
            if (tEntity == null) {
                throw Error.EntityIsTheWrongType();
            } 
            return this.GetModifiedMembers(tEntity);
        } 
 
        private void CheckReadOnly() {
            if (this.IsReadOnly) { 
                throw Error.CannotPerformCUDOnReadOnlyTable(ToString());
            }
        }
 
        public override string ToString() {
            return "Table(" + typeof(TEntity).Name + ")"; 
        } 
    }
 
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ChangeSet", Justification="The capitalization was deliberately chosen.")]
    public sealed class ChangeSet {
        ReadOnlyCollection inserts;
        ReadOnlyCollection deletes; 
        ReadOnlyCollection updates;
 
        internal ChangeSet( 
            ReadOnlyCollection inserts,
            ReadOnlyCollection deletes, 
            ReadOnlyCollection updates
            ) {
            this.inserts = inserts;
            this.deletes = deletes; 
            this.updates = updates;
        } 
 
        public IList Inserts {
            get { return this.inserts; } 
        }

        public IList Deletes {
            get { return this.deletes; } 
        }
 
        public IList Updates { 
            get { return this.updates; }
        } 

        public override string ToString() {
            return "{" +
                string.Format( 
                    Globalization.CultureInfo.InvariantCulture,
                    "Inserts: {0}, Deletes: {1}, Updates: {2}", 
                    this.Inserts.Count, 
                    this.Deletes.Count,
                    this.Updates.Count 
                    ) + "}";
        }
    }
 
    [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "[....]: Types are never compared to each other.  When comparisons happen it is against the entities that are represented by these constructs.")]
    public struct ModifiedMemberInfo { 
        MemberInfo member; 
        object current;
        object original; 

        internal ModifiedMemberInfo(MemberInfo member, object current, object original) {
            this.member = member;
            this.current = current; 
            this.original = original;
        } 
 
        public MemberInfo Member {
            get { return this.member; } 
        }

        public object CurrentValue {
            get { return this.current; } 
        }
 
        public object OriginalValue { 
            get { return this.original; }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

                        

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