DataContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DLinq / Dlinq / DataContext.cs / 1599186 / 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; 
using System.Runtime.CompilerServices; 

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);
            // Technically, calling GC.SuppressFinalize is not required because the class does not
            // have a finalizer, but it does no harm, protects against the case where a finalizer is added 
            // in the future, and prevents an FxCop warning.
            GC.SuppressFinalize(this); 
        } 
        // 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) {
                            transaction.Rollback(); 
                        } 
                        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(); 
                }

                if (trackedObject.IsNew) {
                    throw Error.RefreshOfNewObject(); 
                }
 
                // 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; 
            }
        } 
    } 

    ///  
    /// Defines behavior for implementations of IQueryable that allow modifications to the membership of the resulting set.
    /// 
    /// Type of entities returned from the queryable.
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] 
    public interface ITable : IQueryable
        where TEntity : class 
    { 
        /// 
        /// Notify the set that an object representing a new entity should be added to the set. 
        /// Depending on the implementation, the change to the set may not be visible in an enumeration of the set
        /// until changes to that set have been persisted in some manner.
        /// 
        /// Entity object to be added. 
        void InsertOnSubmit(TEntity entity);
 
        ///  
        /// Notify the set that an object representing a new entity should be added to the set.
        /// Depending on the implementation, the change to the set may not be visible in an enumeration of the set 
        /// until changes to that set have been persisted in some manner.
        /// 
        /// Entity object to be attached.
        void Attach(TEntity entity); 

        ///  
        /// Notify the set that an object representing an entity should be removed from the set. 
        /// Depending on the implementation, the change to the set may not be visible in an enumeration of the set
        /// until changes to that set have been persisted in some manner. 
        /// 
        /// Entity object to be removed.
        /// Throws if the specified object is not in the set.
        void DeleteOnSubmit(TEntity entity); 
    }
 
    ///  
    /// 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, ITable 
        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; 
            } 
        }
 
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        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