EntityConnection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / EntityClient / EntityConnection.cs / 2 / EntityConnection.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
using System.Collections; 
using System.Collections.Generic;
using System.Text; 
using System.Data;
using System.Data.Common;
using System.Data.Common.EntitySql;
using System.Configuration; 
using System.IO;
using System.Diagnostics; 
using System.Data.Metadata; 
using System.Xml;
using System.Data.Mapping; 
using System.Transactions;


namespace System.Data.EntityClient 
{
    using Metadata.Edm; 
 
    /// 
    /// Class representing a connection for the conceptual layer. An entity connection may only 
    /// be initialized once (by opening the connection). It is subsequently not possible to change
    /// the connection string, attach a new store connection, or change the store connection string.
    /// 
    public sealed class EntityConnection : DbConnection 
    {
        #region Constants 
 
        private const string s_metadataPathSeparator    = "|";
        private const string s_semicolonSeparator = ";"; 
        private const string s_entityClientProviderName = "System.Data.EntityClient";
        private const string s_dataDirectory = "|datadirectory|";
        private const string s_metadataid = "metadata id";
        private const string s_providerInvariantName = "provider"; 
        private const string s_providerConnectionString = "provider connection string";
 
        #endregion 

        private readonly object _connectionStringLock = new object(); 
        private static readonly DbConnectionOptions s_emptyConnectionOptions = new DbConnectionOptions(String.Empty, null, false);

        // The connection options object having the connection settings needed by this connection
        private DbConnectionOptions _userConnectionOptions; 
        private DbConnectionOptions _effectiveConnectionOptions;
 
        // The internal connection state of the entity client, which is distinct from that of the 
        // store connection it aggregates.
        private ConnectionState _entityClientConnectionState = ConnectionState.Closed; 

        private DbProviderFactory _providerFactory;
        private DbConnection _storeConnection;
        private MetadataWorkspace _metadataWorkspace; 
        private EntityTransaction _currentTransaction;
        private Guid _metadataID;       //set only when constructed using MetadataWorkspace 
        private bool _initialized; 
        // will only have a value while waiting for the ssdl to be loaded. we should
        // never have a value for this when _initialized == true 
        private MetadataArtifactLoader _artifactLoader;

        private static int _objectTypeCount; // Bid counter
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        /// Constructs the EntityConnection object with a connection not yet associated to a particular store 
        /// 
        public EntityConnection() 
            : this(String.Empty)
        {
        }
 
        /// 
        /// Constructs the EntityConnection object with a connection string 
        ///  
        /// The connection string, may contain a list of settings for the connection or
        /// just the name of the connection to use 
        public EntityConnection(string connectionString)
        {
            GC.SuppressFinalize(this);
            this.ChangeConnectionString(connectionString); 
        }
 
        ///  
        /// Constructs the EntityConnection from Metadata loaded in memory
        ///  
        /// Workspace containing metadata information.
        public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
        {
            EntityUtil.CheckArgumentNull(workspace, "workspace"); 
            EntityUtil.CheckArgumentNull(connection, "connection");
 
 
            if (!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace))
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("EdmItemCollection"));
            }
            if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StoreItemCollection"));
            } 
            if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace)) 
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StorageMappingItemCollection")); 
            }

            if (connection.State != ConnectionState.Closed)
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionMustBeClosed);
            } 
 
            if (connection.ProviderFactory == null)
            { 
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_DbConnectionHasNoProvider(connection));
            }

            StoreItemCollection collection = (StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace); 
            ValidateThatConnectionAndMetadataProvidersAreEqual(connection.ProviderFactory, null, collection.StoreProviderFactory);
 
            GC.SuppressFinalize(this); 

            _providerFactory = connection.ProviderFactory; 
            _storeConnection = connection;
            _metadataWorkspace = workspace;
            _initialized = true;
            _metadataID = System.Guid.NewGuid(); 

        } 
 
        /// 
        /// Get or set the entity connection string associated with this connection object 
        /// 
        public override string ConnectionString
        {
            get 
            {
                //EntityConnection created using MetadataWorkspace 
                // _userConnectionOptions is not null when empty Constructor is used 
                // Therefore it is sufficient to identify whether EC(MW, DbConnection) is used
                if (this._userConnectionOptions == null) 
                {
                    Debug.Assert(_storeConnection != null);

                    string invariantName; 
                    if(!EntityUtil.TryGetProviderInvariantName(_storeConnection.ProviderFactory, out invariantName))
                    { 
                        Debug.Fail("Provider Invariant Name not found"); 
                        invariantName = "";
                    } 

                    return string.Format(Globalization.CultureInfo.InvariantCulture,
                        "{0}={3};{1}={4};{2}=\"{5}\";",
                        s_metadataid, 
                        s_providerInvariantName,
                        s_providerConnectionString, 
                        _metadataID.ToString(), 
                        invariantName,
                        FormatProviderString(_storeConnection.ConnectionString)); 
                }

                string userConnectionString = this._userConnectionOptions.UsersConnectionString(false);
 
                // In here, we ask the store connection for the connection string only if the user didn't specify a name
                // connection (meaning effective connection options == user connection options).  If the user specified a 
                // named connection, then we return just that.  Otherwise, if the connection string is different from what 
                // we have in the connection options, which is possible if the store connection changed the connection
                // string to hide the password, then we use the builder to reconstruct the string. The parameters will be 
                // shuffled, which is unavoidable but it's ok because the connection string cannot be the same as what the
                // user originally passed in anyway.  However, if the store connection string is still the same, then we
                // simply return what the user originally passed in.
                if (object.ReferenceEquals(_userConnectionOptions, _effectiveConnectionOptions) && this._storeConnection != null) 
                {
                    string storeConnectionString = null; 
                    try 
                    {
                        storeConnectionString = this._storeConnection.ConnectionString; 
                    }
                    catch (Exception e)
                    {
                        if (EntityUtil.IsCatchableExceptionType(e)) 
                        {
                            throw EntityUtil.Provider(@"ConnectionString", e); 
                        } 
                        throw;
                    } 

                    // SQLBU 514721, 515024 - Defer connection string parsing to ConnectionStringBuilder
                    // if the 'userStoreConnectionString' and 'storeConnectionString' are unequal, except
                    // when they are both null or empty (we treat null and empty as equivalent here). 
                    //
                    string userStoreConnectionString = this._userConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName]; 
                    if ((storeConnectionString != userStoreConnectionString) 
                        && !(string.IsNullOrEmpty(storeConnectionString) && string.IsNullOrEmpty(userStoreConnectionString)))
                    { 
                        // Feeds the connection string into the connection string builder, then plug in the provider connection string into
                        // the builder, and then extract the string from the builder
                        EntityConnectionStringBuilder connectionStringBuilder = new EntityConnectionStringBuilder(userConnectionString);
                        connectionStringBuilder.ProviderConnectionString = storeConnectionString; 
                        return connectionStringBuilder.ConnectionString;
                    } 
                } 

                return userConnectionString; 
            }
            set
            {
                ValidateChangesPermitted(); 
                this.ChangeConnectionString(value);
            } 
        } 

        ///  
        /// Formats provider string to replace " with \" so it can be appended within quotation marks "..."
        /// 
        private static string FormatProviderString(string providerString)
        { 
            return providerString.Trim().Replace("\"", "\\\"");
        } 
 
        /// 
        /// Get the time to wait when attempting to establish a connection before ending the try and generating an error 
        /// 
        public override int ConnectionTimeout
        {
            get 
            {
                if (this._storeConnection == null) 
                    return 0; 

                try 
                {
                    return this._storeConnection.ConnectionTimeout;
                }
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    { 
                        throw EntityUtil.Provider(@"ConnectionTimeout", e);
                    } 
                    throw;
                }
            }
        } 

        ///  
        /// Get the name of the current database or the database that will be used after a connection is opened 
        /// 
        public override string Database 
        {
            get
            {
                return String.Empty; 
            }
        } 
 
        /// 
        /// Gets the ConnectionState property of the EntityConnection 
        /// 
        public override ConnectionState State
        {
            get 
            {
                try 
                { 
                    if (this._entityClientConnectionState == ConnectionState.Open)
                    { 
                        Debug.Assert(this.StoreConnection != null);
                        if (this.StoreConnection.State != ConnectionState.Open)
                        {
                            return ConnectionState.Broken; 
                        }
                    } 
                    return this._entityClientConnectionState; 
                }
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e))
                    {
                        throw EntityUtil.Provider(@"State", e); 
                    }
                    throw; 
                } 
            }
        } 

        /// 
        /// Gets the name or network address of the data source to connect to
        ///  
        public override string DataSource
        { 
            get 
            {
                if (this._storeConnection == null) 
                    return String.Empty;

                try
                { 
                    return this._storeConnection.DataSource;
                } 
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    {
                        throw EntityUtil.Provider(@"DataSource", e);
                    }
                    throw; 
                }
            } 
        } 

        ///  
        /// Gets a string that contains the version of the data store to which the client is connected
        /// 
        public override string ServerVersion
        { 
            get
            { 
                if (this._storeConnection == null) 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
 
                if (this.State != ConnectionState.Open)
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
                } 

                try 
                { 
                    return this._storeConnection.ServerVersion;
                } 
                catch (Exception e)
                {
                    if (EntityUtil.IsCatchableExceptionType(e))
                    { 
                        throw EntityUtil.Provider(@"ServerVersion", e);
                    } 
                    throw; 
                }
            } 
        }

        /// 
        /// Gets the provider factory associated with EntityConnection 
        /// 
        override protected DbProviderFactory DbProviderFactory 
        { 
            get
            { 
                return EntityProviderFactory.Instance;
            }
        }
 
        /// 
        /// Gets the DbProviderFactory for the underlying provider 
        ///  
        internal DbProviderFactory StoreProviderFactory
        { 
            get
            {
                return this._providerFactory;
            } 
        }
 
        ///  
        /// Gets the DbConnection for the underlying provider connection
        ///  
        public DbConnection StoreConnection
        {
            get
            { 
                return this._storeConnection;
            } 
        } 

        ///  
        /// Gets the metadata workspace used by this connection
        /// 
        public MetadataWorkspace GetMetadataWorkspace()
        { 
            return GetMetadataWorkspace(true /* initializeAllCollections */);
        } 
 
        internal MetadataWorkspace GetMetadataWorkspace(bool initializeAllCollections)
        { 
            Debug.Assert(_metadataWorkspace != null || _effectiveConnectionOptions != null, "The effective connection options is null, which should never be");
            if (_metadataWorkspace == null ||
                (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)))
            { 
                // This lock is to ensure that the connection string and the metadata workspace are in a consistent state, that is, you
                // don't get a metadata workspace not matching what's described by the connection string 
                lock (_connectionStringLock) 
                {
                    EdmItemCollection edmItemCollection = null; 
                    if (_metadataWorkspace == null)
                    {
                        MetadataWorkspace workspace = new MetadataWorkspace();
 
                        _artifactLoader = SplitPaths(_effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName]);
                        edmItemCollection = LoadEdmItemCollection(workspace, _artifactLoader); 
                        _metadataWorkspace = workspace; 
                    }
                    else 
                    {
                        edmItemCollection = (EdmItemCollection)_metadataWorkspace.GetItemCollection(DataSpace.CSpace);
                    }
 
                    if (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
                    { 
                        LoadStoreItemCollections(_metadataWorkspace, _storeConnection, _providerFactory, _effectiveConnectionOptions, edmItemCollection, _artifactLoader); 
                        _artifactLoader = null;
                        _initialized = true; 
                    }
                }
            }
 
            return _metadataWorkspace;
        } 
 
        /// 
        /// Gets the current transaction that this connection is enlisted in 
        /// 
        internal EntityTransaction CurrentTransaction
        {
            get 
            {
                // Null out the current transaction if the state is closed or zombied 
                if ((null != _currentTransaction) && ((null == _currentTransaction.StoreTransaction.Connection) || (this.State == ConnectionState.Closed))) 
                {
                    ClearCurrentTransaction(); 
                }
                return _currentTransaction;
            }
        } 

        ///  
        /// Establish a connection to the data store by calling the Open method on the underlying data provider 
        /// 
        public override void Open() 
        {
            if (this._storeConnection == null)
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
 
            if (this.State != ConnectionState.Closed)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_CannotReopenConnection); 
            }
 
            bool closeStoreConnectionOnFailure = false;
            OpenStoreConnectionIf(this._storeConnection.State != ConnectionState.Open,
                                  this._storeConnection,
                                  null, 
                                  EntityRes.EntityClient_ProviderSpecificError,
                                  @"Open", 
                                  ref closeStoreConnectionOnFailure); 

            // the following guards against the case when the user closes the underlying store connection 
            // in the state change event handler, as a consequence of which we are in the 'Broken' state
            if (this._storeConnection == null || this._storeConnection.State != ConnectionState.Open)
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen); 
            }
 
            InitializeMetadata(this._storeConnection, this._storeConnection, closeStoreConnectionOnFailure); 
            SetEntityClientConnectionStateToOpen();
        } 

        /// 
        /// Helper method that conditionally opens a specified store connection
        ///  
        /// The condition to evaluate
        /// The store connection to open 
        /// The original store connection associated with the entity client 
        /// A flag that is set on if the connection is opened
        /// successfully 
        private void OpenStoreConnectionIf(bool openCondition,
                                           DbConnection storeConnectionToOpen,
                                           DbConnection originalConnection,
                                           string exceptionCode, 
                                           string attemptedOperation,
                                           ref bool closeStoreConnectionOnFailure) 
        { 
            try
            { 
                if (openCondition)
                {
                    storeConnectionToOpen.Open();
                    closeStoreConnectionOnFailure = true; 
                }
 
                ResetStoreConnection(storeConnectionToOpen, originalConnection, false); 

                // With every successful open of the store connection, always null out the current 
                // transaction (if there is one)
                ClearCurrentTransaction();
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    string exceptionMessage = string.IsNullOrEmpty(attemptedOperation) ?
                        EntityRes.GetString(exceptionCode) : 
                        EntityRes.GetString(exceptionCode, attemptedOperation);

                    throw EntityUtil.ProviderExceptionWithMessage(exceptionMessage, e);
                } 
                throw;
            } 
        } 

        ///  
        /// Helper method to initialize the metadata workspace and reset the store connection
        /// associated with the entity client
        /// 
        /// The new connection to associate with the entity client 
        /// The original connection associated with the entity client
        /// A flag to indicate whether the original 
        /// store connection needs to be closed on failure 
        private void InitializeMetadata(DbConnection newConnection,
                                        DbConnection originalConnection, 
                                        bool closeOriginalConnectionOnFailure)
        {
            try
            { 
                // Ensure metadata is loaded and the workspace is appropriately initialized.
                GetMetadataWorkspace(); 
            } 
            catch (Exception ex)
            { 
                // Undo the open if something failed
                if (EntityUtil.IsCatchableExceptionType(ex))
                {
                    ResetStoreConnection(newConnection, originalConnection, closeOriginalConnectionOnFailure); 
                }
                throw; 
            } 
        }
 
        /// 
        /// Set the entity client connection state to Open, and raise an appropriate event
        /// 
        private void SetEntityClientConnectionStateToOpen() 
        {
            this._entityClientConnectionState = ConnectionState.Open; 
            OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeOpen); 
        }
 
        /// 
        /// This method sets the store connection and hooks up the event
        /// 
        /// The  DbConnection to set 
        /// The original DbConnection to be closed - this argument could be null
        /// Indicates whether the original store connection should be closed 
        private void ResetStoreConnection(DbConnection newConnection, DbConnection originalConnection, bool closeOriginalConnection) 
        {
            this._storeConnection = newConnection; 

            if (closeOriginalConnection && (originalConnection != null))
            {
                originalConnection.Close(); 
            }
        } 
 
        /// 
        /// Create a new command object that uses this connection object 
        /// 
        public new EntityCommand CreateCommand()
        {
            return new EntityCommand(null, this); 
        }
 
        ///  
        /// Create a new command object that uses this connection object
        ///  
        protected override DbCommand CreateDbCommand()
        {
            return this.CreateCommand();
        } 

        internal EntityConnection Clone() 
        { 
            return new EntityConnection(_userConnectionOptions.UsersConnectionString(false));
        } 

        /// 
        /// Close the connection to the data store
        ///  
        public override void Close()
        { 
            // It's a no-op if there isn't an underlying connection 
            if (this._storeConnection == null)
                return; 

            this.CloseHelper();
        }
 
        /// 
        /// Changes the current database for this connection 
        ///  
        /// The name of the database to change to
        public override void ChangeDatabase(string databaseName) 
        {
            throw EntityUtil.NotSupported();
        }
 
        /// 
        /// Begins a database transaction 
        ///  
        /// An object representing the new transaction
        public new EntityTransaction BeginTransaction() 
        {
            return base.BeginTransaction() as EntityTransaction;
        }
 
        /// 
        /// Begins a database transaction 
        ///  
        /// The isolation level of the transaction
        /// An object representing the new transaction 
        public new EntityTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            return base.BeginTransaction(isolationLevel) as EntityTransaction;
        } 

        ///  
        /// Begins a database transaction 
        /// 
        /// The isolation level of the transaction 
        /// An object representing the new transaction
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            if (CurrentTransaction != null) 
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_TransactionAlreadyStarted); 
            } 

            if (this._storeConnection == null) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);

            if (this.State != ConnectionState.Open)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
            } 
 
            DbTransaction storeTransaction = null;
            try 
            {
                storeTransaction = this._storeConnection.BeginTransaction(isolationLevel);
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    throw EntityUtil.ProviderExceptionWithMessage(
                                            System.Data.Entity.Strings.EntityClient_ErrorInBeginningTransaction, 
                                            e
                                        );
                }
                throw; 
            }
 
            // The provider is problematic if it succeeded in beginning a transaction but returned a null 
            // for the transaction object
            if (storeTransaction == null) 
            {
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("BeginTransaction", _storeConnection.GetType().Name));
            }
 
            _currentTransaction = new EntityTransaction(this, storeTransaction);
            return _currentTransaction; 
        } 

        ///  
        /// Enlist in the given transaction
        /// 
        /// The transaction object to enlist into
        public override void EnlistTransaction(Transaction transaction) 
        {
            if (_storeConnection == null) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation); 

            if (this.State != ConnectionState.Open) 
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
            }
 
            try
            { 
                _storeConnection.EnlistTransaction(transaction); 
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e))
                {
                    throw EntityUtil.Provider(@"EnlistTransaction", e); 
                }
                throw; 
            } 
        }
 
        /// 
        /// Cleans up this connection object
        /// 
        /// true to release both managed and unmanaged resources; false to release only unmanaged resources 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_currentTransaction")]
        protected override void Dispose(bool disposing) 
        { 
            ClearCurrentTransaction();
            bool raiseStateChangeEvent = EntityCloseHelper(false, this.State); 

            if (disposing)
            {
                if (this._storeConnection != null) 
                {
                    StoreCloseHelper(); // closes store connection 
                    if (this._storeConnection != null) 
                    {
                        this._storeConnection.Dispose(); 
                        this._storeConnection = null;
                    }
                }
            } 

            // Change the connection string to just an empty string, ChangeConnectionString should always succeed here, 
            // it's unnecessary to pass in the connection string parameter name in the second argument, which we don't 
            // have anyway
            this.ChangeConnectionString(String.Empty); 

            if (raiseStateChangeEvent)  // we need to raise the event explicitly
            {
                OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed); 
            }
 
            base.Dispose(disposing); 
        }
 
        /// 
        /// Reinitialize this connection object to use the new connection string
        /// 
        /// The new connection string 
        private void ChangeConnectionString(string newConnectionString)
        { 
            DbConnectionOptions userConnectionOptions = s_emptyConnectionOptions; 
            if (!String.IsNullOrEmpty(newConnectionString))
            { 
                userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.Synonyms, false);
            }

            DbProviderFactory factory = null; 
            DbConnection storeConnection = null;
            DbConnectionOptions effectiveConnectionOptions = userConnectionOptions; 
 
            if (!userConnectionOptions.IsEmpty)
            { 
                // Check if we have the named connection, if yes, then use the connection string from the configuration manager settings
                string namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
                if (!string.IsNullOrEmpty(namedConnection))
                { 
                    // There cannot be other parameters when the named connection is specified
                    if (1 < userConnectionOptions.Parsetable.Count) 
                    { 
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ExtraParametersWithNamedConnection);
                    } 

                    // Find the named connection from the configuration, then extract the settings
                    ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[namedConnection];
                    if (setting == null || setting.ProviderName != EntityConnection.s_entityClientProviderName) 
                    {
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidNamedConnection); 
                    } 

                    effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms, false); 

                    // Check for a nested Name keyword
                    string nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
                    if (!string.IsNullOrEmpty(nestedNamedConnection)) 
                    {
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_NestedNamedConnection(namedConnection)); 
                    } 
                }
 
                //Validate the connection string has the required Keywords( Provider and Metadata)
                //We trim the values for both the Keywords, so a string value with only spaces will throw an exception
                //reporting back to the user that the Keyword was missing.
                ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName); 

                string providerName = ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName); 
                // Get the correct provider factory 
                factory = GetFactory(providerName);
 
                // Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object
                storeConnection = GetStoreConnection(factory);

                try 
                {
                    // When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all. 
                    // Providers should still be able handle empty connection strings since those may be explicitly passed by clients. 
                    string providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
                    if (providerConnectionString != null) 
                    {
                        storeConnection.ConnectionString = providerConnectionString;
                    }
                } 
                catch (Exception e)
                { 
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    {
                        throw EntityUtil.Provider(@"ConnectionString", e); 
                    }
                    throw;
                }
            } 

            // This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being 
            // managed by this EntityConnection, so states in this connection object are not messed up. 
            // It's not for security, but just to help reduce user error.
            lock (_connectionStringLock) 
            {
                // Now we have sufficient information and verified the configuration string is good, use them for this connection object
                // Failure should not occur from this point to the end of this method
                this._providerFactory = factory; 
                this._metadataWorkspace = null;
 
                ClearCurrentTransaction(); 

                ResetStoreConnection(storeConnection, null, false); 

                // Remembers the connection options objects with the connection string set by the user
                this._userConnectionOptions = userConnectionOptions;
                this._effectiveConnectionOptions = effectiveConnectionOptions; 
            }
        } 
 
        private static string ValidateValueForTheKeyword(DbConnectionOptions effectiveConnectionOptions,
            string keywordName) 
        {
            string keywordValue = effectiveConnectionOptions[keywordName];
            if (!string.IsNullOrEmpty(keywordValue))
                keywordValue = keywordValue.Trim(); // be nice to user, always trim the value 

            // Check that we have a non-null and non-empty value for the keyword 
            if (string.IsNullOrEmpty(keywordValue)) 
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionStringMissingInfo(keywordName)); 
            }
            return keywordValue;
        }
 
        private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspace, MetadataArtifactLoader artifactLoader)
        { 
            // Build a string as the key and look up the MetadataCache for a match 
            string edmCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
 
            // Check the MetadataCache for an entry with this key
            object entryToken;
            EdmItemCollection edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(edmCacheKey,
                                                                                        artifactLoader, 
                                                                                        out entryToken);
            workspace.RegisterItemCollection(edmItemCollection); 
 
            // Adding the edm metadata entry token to the workspace, to make sure that this token remains alive till workspace is alive
            workspace.AddMetadataEntryToken(entryToken); 

            return edmItemCollection;
        }
 
        private static void LoadStoreItemCollections(MetadataWorkspace workspace,
                                                     DbConnection storeConnection, 
                                                     DbProviderFactory factory, 
                                                     DbConnectionOptions connectionOptions,
                                                     EdmItemCollection edmItemCollection, 
                                                     MetadataArtifactLoader artifactLoader)
        {
            Debug.Assert(workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space");
 
            // The provider connection string is optional; if it has not been specified,
            // we pick up the store's connection string. 
            // 
            string providerConnectionString = connectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
            if (string.IsNullOrEmpty(providerConnectionString) && (storeConnection != null)) 
            {
                providerConnectionString = storeConnection.ConnectionString;
            }
 
            // Build a string as the key and look up the MetadataCache for a match
            string storeCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(), 
                                                          connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], 
                                                          providerConnectionString);
 
            // Load store metadata.
            object entryToken;
            StorageMappingItemCollection mappingCollection =
                MetadataCache.GetOrCreateStoreAndMappingItemCollections(storeCacheKey, 
                                                                     artifactLoader,
                                                                     edmItemCollection, 
                                                                     out entryToken); 

            ValidateThatConnectionAndMetadataProvidersAreEqual(factory, connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], mappingCollection.StoreItemCollection.StoreProviderFactory); 
            workspace.RegisterItemCollection(mappingCollection.StoreItemCollection);
            workspace.RegisterItemCollection(mappingCollection);

            // Adding the store metadata entry token to the workspace 
            workspace.AddMetadataEntryToken(entryToken);
        } 
 
        private static void ValidateThatConnectionAndMetadataProvidersAreEqual(DbProviderFactory connectionFactory, string connectionProviderName, DbProviderFactory metadataFactory)
        { 
            if (metadataFactory.GetType() != connectionFactory.GetType())
            {
                string metadataProviderName = GetErrorMessageWorthyProviderName(metadataFactory);
 
                if (string.IsNullOrEmpty(connectionProviderName))
                { 
                    connectionProviderName = GetErrorMessageWorthyProviderName(connectionFactory); 
                }
 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionAndMetadataProviderMismatch(metadataProviderName, connectionProviderName));
            }
        }
 
        private static string GetErrorMessageWorthyProviderName(DbProviderFactory factory)
        { 
            EntityUtil.CheckArgumentNull(factory, "factory"); 

            string providerName; 
            if (!EntityUtil.TryGetProviderInvariantName(factory, out providerName))
            {
                providerName = factory.GetType().FullName;
            } 
            return providerName;
        } 
 
        /// 
        /// Create a key to be used with the MetadataCache from a connection options object 
        /// 
        /// A list of metadata file paths
        /// The provider name
        /// The provider connection string 
        /// The key
        private static string CreateMetadataCacheKey(IList paths, string providerName, string providerConnectionString) 
        { 
            int resultCount = 0;
            string result; 

            // Do a first pass to calculate the output size of the metadata cache key,
            // then another pass to populate a StringBuilder with the exact size and
            // get the result. 
            CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
                false, ref resultCount, out result); 
            CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString, 
                true, ref resultCount, out result);
 
            return result;
        }

        ///  
        /// Create a key to be used with the MetadataCache from a connection options
        /// object. 
        ///  
        /// A list of metadata file paths
        /// The provider name 
        /// The provider connection string
        /// Whether the result variable should be built.
        /// 
        /// On entry, the expected size of the result (unused if buildResult is false). 
        /// After execution, the effective result.
        /// The key. 
        ///  
        /// This method should be called once with buildResult=false, to get
        /// the size of the resulting key, and once with buildResult=true 
        /// and the size specification.
        /// 
        private static void CreateMetadataCacheKeyWithCount(IList paths,
            string providerName, string providerConnectionString, 
            bool buildResult, ref int resultCount, out string result)
        { 
            // Build a string as the key and look up the MetadataCache for a match 
            StringBuilder keyString;
            if (buildResult) 
            {
                keyString = new StringBuilder(resultCount);
            }
            else 
            {
                keyString = null; 
            } 

            // At this point, we've already used resultCount. Reset it 
            // to zero to make the final debug assertion that our computation
            // is correct.
            resultCount = 0;
 
            if (!string.IsNullOrEmpty(providerName))
            { 
                resultCount += providerName.Length + 1; 
                if (buildResult)
                { 
                    keyString.Append(providerName);
                    keyString.Append(EntityConnection.s_semicolonSeparator);
                }
            } 

            if (paths != null) 
            { 
                for (int i = 0; i < paths.Count; i++)
                { 
                    if (paths[i].Length > 0)
                    {
                        if (i > 0)
                        { 
                            resultCount++;
                            if (buildResult) 
                            { 
                                keyString.Append(EntityConnection.s_metadataPathSeparator);
                            } 
                        }
                        resultCount += paths[i].Length;
                        if (buildResult)
                        { 
                            keyString.Append(paths[i]);
                        } 
                    } 
                }
                resultCount++; 
                if (buildResult)
                {
                    keyString.Append(EntityConnection.s_semicolonSeparator);
                } 
            }
 
            if (!string.IsNullOrEmpty(providerConnectionString)) 
            {
                resultCount += providerConnectionString.Length; 
                if (buildResult)
                {
                    keyString.Append(providerConnectionString);
                } 
            }
 
            if (buildResult) 
            {
                result = keyString.ToString(); 
            }
            else
            {
                result = null; 
            }
 
            System.Diagnostics.Debug.Assert( 
                !buildResult || (result.Length == resultCount));
        } 

        /// 
        /// A helper function for splitting up a string that is a concatenation of strings delimited by the metadata
        /// path separator into a string list. The resulting list is NOT sorted. 
        /// 
        /// The paths to split 
        /// An array of strings 
        private static MetadataArtifactLoader SplitPaths(string paths)
        { 
            string[] results;

            // This is the registry of all URIs in the global collection.
            HashSet uriRegistry = new HashSet(StringComparer.OrdinalIgnoreCase); 

            List loaders = new List(); 
 
            if (!string.IsNullOrEmpty(paths))
            { 
                // If the argument contains one or more occurrences of the macro '|DataDirectory|', we
                // pull those paths out so that we don't lose them in the string-splitting logic below.
                // Note that the macro '|DataDirectory|' cannot have any whitespace between the pipe
                // symbols and the macro name. Also note that the macro must appear at the beginning of 
                // a path (else we will eventually fail with an invalid path exception, because in that
                // case the macro is not expanded). If a real/physical folder named 'DataDirectory' needs 
                // to be included in the metadata path, whitespace should be used on either or both sides 
                // of the name.
                // 
                List dataDirPaths = new List();

                int indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
                while (indexStart != -1) 
                {
                    int prevSeparatorIndex = indexStart == 0 ? -1 : paths.LastIndexOf( 
                                                                    EntityConnection.s_metadataPathSeparator, 
                                                                    indexStart - 1, // start looking here
                                                                    StringComparison.Ordinal 
                                                                );

                    int macroPathBeginIndex = prevSeparatorIndex + 1;
 
                    // The '|DataDirectory|' macro is composable, so identify the complete path, like
                    // '|DataDirectory|\foo\bar'. If the macro appears anywhere other than at the 
                    // beginning, splice out the entire path, e.g. 'C:\foo\|DataDirectory|\bar'. In this 
                    // latter case the macro will not be expanded, and downstream code will throw an exception.
                    // 
                    int indexEnd = paths.IndexOf(EntityConnection.s_metadataPathSeparator,
                                                 indexStart + EntityConnection.s_dataDirectory.Length,
                                                 StringComparison.Ordinal);
                    if (indexEnd == -1) 
                    {
                        dataDirPaths.Add(paths.Substring(macroPathBeginIndex)); 
                        paths = paths.Remove(macroPathBeginIndex);   // update the concatenated list of paths 
                        break;
                    } 

                    dataDirPaths.Add(paths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex));

                    // Update the concatenated list of paths by removing the one containing the macro. 
                    //
                    paths = paths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex); 
                    indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase); 
                }
 
                // Split the string on the separator and remove all spaces around each parameter value
                results = paths.Split(new string[] { EntityConnection.s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries);

                // Now that the non-macro paths have been identified, merge the paths containing the macro 
                // into the complete list.
                // 
                if (dataDirPaths.Count > 0) 
                {
                    dataDirPaths.AddRange(results); 
                    results = dataDirPaths.ToArray();
                }

                for (int i = 0; i < results.Length; i++) 
                {
                    // Trim out all the spaces for this parameter and add it only if it's not blank 
                    results[i] = results[i].Trim(); 
                    if (results[i].Length > 0)
                    { 
                        loaders.Add(MetadataArtifactLoader.Create(
                                        results[i],
                                        MetadataArtifactLoader.ExtensionCheck.All,  // validate the extension against all acceptable values
                                        null, 
                                        uriRegistry
                                    )); 
                    } 
                }
            } 

            return MetadataArtifactLoader.Create(loaders);
        }
 
        /// 
        /// Clears the current transaction for this connection 
        ///  
        internal void ClearCurrentTransaction()
        { 
            _currentTransaction = null;
        }

        ///  
        /// Helper method invoked as part of Close()/Dispose() that releases the underlying
        /// store connection and raises the appropriate event. 
        ///  
        private void CloseHelper()
        { 
            ConnectionState previousState = this.State; // the public connection state before cleanup
            StoreCloseHelper();
            EntityCloseHelper(
                            true,   // raise the state change event 
                            previousState
                        ); 
        } 

        ///  
        /// Store-specific helper method invoked as part of Close()/Dispose().
        /// 
        private void StoreCloseHelper()
        { 
            try
            { 
                if (this._storeConnection != null && (this._storeConnection.State != ConnectionState.Closed)) 
                {
                    this._storeConnection.Close(); 
                }
                // Need to disassociate the transaction object with this connection
                ClearCurrentTransaction();
            } 
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e)) 
                {
                    throw EntityUtil.ProviderExceptionWithMessage( 
                                        System.Data.Entity.Strings.EntityClient_ErrorInClosingConnection,
                                        e
                                    );
                } 
                throw;
            } 
        } 

        ///  
        /// Entity-specific helper method invoked as part of Close()/Dispose().
        /// 
        /// Indicates whether we need to raise the state change event here
        /// The public state of the connection before cleanup began 
        /// true if the caller needs to raise the state change event
        private bool EntityCloseHelper(bool fireEventOnStateChange, ConnectionState previousState) 
        { 
            bool result = false;
 
            this._entityClientConnectionState = ConnectionState.Closed;

            if (previousState == ConnectionState.Open)
            { 
                if (fireEventOnStateChange)
                { 
                    OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed); 
                }
                else 
                {
                    result = true;  // we didn't raise the event here; the caller should do that
                }
            } 

            return result; 
        } 

        ///  
        /// Call to determine if changes to the entity object are currently permitted.
        /// 
        private void ValidateChangesPermitted()
        { 
            if (_initialized)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_SettingsCannotBeChangedOnOpenConnection); 
            }
        } 

        /// 
        /// Returns the DbProviderFactory associated with specified provider string
        ///  
        private DbProviderFactory GetFactory(string providerString)
        { 
            try 
            {
                return DbProviderFactories.GetFactory(providerString); 
            }
            catch (ArgumentException e)
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidStoreProvider, e); 
            }
        } 
 
        /// 
        /// Uses DbProviderFactory to create a DbConnection 
        /// 
        private DbConnection GetStoreConnection(DbProviderFactory factory)
        {
            DbConnection storeConnection = factory.CreateConnection(); 
            if (storeConnection == null)
            { 
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("CreateConnection", factory.GetType().Name)); 
            }
            return storeConnection; 
        }

    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
using System.Collections; 
using System.Collections.Generic;
using System.Text; 
using System.Data;
using System.Data.Common;
using System.Data.Common.EntitySql;
using System.Configuration; 
using System.IO;
using System.Diagnostics; 
using System.Data.Metadata; 
using System.Xml;
using System.Data.Mapping; 
using System.Transactions;


namespace System.Data.EntityClient 
{
    using Metadata.Edm; 
 
    /// 
    /// Class representing a connection for the conceptual layer. An entity connection may only 
    /// be initialized once (by opening the connection). It is subsequently not possible to change
    /// the connection string, attach a new store connection, or change the store connection string.
    /// 
    public sealed class EntityConnection : DbConnection 
    {
        #region Constants 
 
        private const string s_metadataPathSeparator    = "|";
        private const string s_semicolonSeparator = ";"; 
        private const string s_entityClientProviderName = "System.Data.EntityClient";
        private const string s_dataDirectory = "|datadirectory|";
        private const string s_metadataid = "metadata id";
        private const string s_providerInvariantName = "provider"; 
        private const string s_providerConnectionString = "provider connection string";
 
        #endregion 

        private readonly object _connectionStringLock = new object(); 
        private static readonly DbConnectionOptions s_emptyConnectionOptions = new DbConnectionOptions(String.Empty, null, false);

        // The connection options object having the connection settings needed by this connection
        private DbConnectionOptions _userConnectionOptions; 
        private DbConnectionOptions _effectiveConnectionOptions;
 
        // The internal connection state of the entity client, which is distinct from that of the 
        // store connection it aggregates.
        private ConnectionState _entityClientConnectionState = ConnectionState.Closed; 

        private DbProviderFactory _providerFactory;
        private DbConnection _storeConnection;
        private MetadataWorkspace _metadataWorkspace; 
        private EntityTransaction _currentTransaction;
        private Guid _metadataID;       //set only when constructed using MetadataWorkspace 
        private bool _initialized; 
        // will only have a value while waiting for the ssdl to be loaded. we should
        // never have a value for this when _initialized == true 
        private MetadataArtifactLoader _artifactLoader;

        private static int _objectTypeCount; // Bid counter
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        /// Constructs the EntityConnection object with a connection not yet associated to a particular store 
        /// 
        public EntityConnection() 
            : this(String.Empty)
        {
        }
 
        /// 
        /// Constructs the EntityConnection object with a connection string 
        ///  
        /// The connection string, may contain a list of settings for the connection or
        /// just the name of the connection to use 
        public EntityConnection(string connectionString)
        {
            GC.SuppressFinalize(this);
            this.ChangeConnectionString(connectionString); 
        }
 
        ///  
        /// Constructs the EntityConnection from Metadata loaded in memory
        ///  
        /// Workspace containing metadata information.
        public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
        {
            EntityUtil.CheckArgumentNull(workspace, "workspace"); 
            EntityUtil.CheckArgumentNull(connection, "connection");
 
 
            if (!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace))
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("EdmItemCollection"));
            }
            if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StoreItemCollection"));
            } 
            if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace)) 
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StorageMappingItemCollection")); 
            }

            if (connection.State != ConnectionState.Closed)
            { 
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionMustBeClosed);
            } 
 
            if (connection.ProviderFactory == null)
            { 
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_DbConnectionHasNoProvider(connection));
            }

            StoreItemCollection collection = (StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace); 
            ValidateThatConnectionAndMetadataProvidersAreEqual(connection.ProviderFactory, null, collection.StoreProviderFactory);
 
            GC.SuppressFinalize(this); 

            _providerFactory = connection.ProviderFactory; 
            _storeConnection = connection;
            _metadataWorkspace = workspace;
            _initialized = true;
            _metadataID = System.Guid.NewGuid(); 

        } 
 
        /// 
        /// Get or set the entity connection string associated with this connection object 
        /// 
        public override string ConnectionString
        {
            get 
            {
                //EntityConnection created using MetadataWorkspace 
                // _userConnectionOptions is not null when empty Constructor is used 
                // Therefore it is sufficient to identify whether EC(MW, DbConnection) is used
                if (this._userConnectionOptions == null) 
                {
                    Debug.Assert(_storeConnection != null);

                    string invariantName; 
                    if(!EntityUtil.TryGetProviderInvariantName(_storeConnection.ProviderFactory, out invariantName))
                    { 
                        Debug.Fail("Provider Invariant Name not found"); 
                        invariantName = "";
                    } 

                    return string.Format(Globalization.CultureInfo.InvariantCulture,
                        "{0}={3};{1}={4};{2}=\"{5}\";",
                        s_metadataid, 
                        s_providerInvariantName,
                        s_providerConnectionString, 
                        _metadataID.ToString(), 
                        invariantName,
                        FormatProviderString(_storeConnection.ConnectionString)); 
                }

                string userConnectionString = this._userConnectionOptions.UsersConnectionString(false);
 
                // In here, we ask the store connection for the connection string only if the user didn't specify a name
                // connection (meaning effective connection options == user connection options).  If the user specified a 
                // named connection, then we return just that.  Otherwise, if the connection string is different from what 
                // we have in the connection options, which is possible if the store connection changed the connection
                // string to hide the password, then we use the builder to reconstruct the string. The parameters will be 
                // shuffled, which is unavoidable but it's ok because the connection string cannot be the same as what the
                // user originally passed in anyway.  However, if the store connection string is still the same, then we
                // simply return what the user originally passed in.
                if (object.ReferenceEquals(_userConnectionOptions, _effectiveConnectionOptions) && this._storeConnection != null) 
                {
                    string storeConnectionString = null; 
                    try 
                    {
                        storeConnectionString = this._storeConnection.ConnectionString; 
                    }
                    catch (Exception e)
                    {
                        if (EntityUtil.IsCatchableExceptionType(e)) 
                        {
                            throw EntityUtil.Provider(@"ConnectionString", e); 
                        } 
                        throw;
                    } 

                    // SQLBU 514721, 515024 - Defer connection string parsing to ConnectionStringBuilder
                    // if the 'userStoreConnectionString' and 'storeConnectionString' are unequal, except
                    // when they are both null or empty (we treat null and empty as equivalent here). 
                    //
                    string userStoreConnectionString = this._userConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName]; 
                    if ((storeConnectionString != userStoreConnectionString) 
                        && !(string.IsNullOrEmpty(storeConnectionString) && string.IsNullOrEmpty(userStoreConnectionString)))
                    { 
                        // Feeds the connection string into the connection string builder, then plug in the provider connection string into
                        // the builder, and then extract the string from the builder
                        EntityConnectionStringBuilder connectionStringBuilder = new EntityConnectionStringBuilder(userConnectionString);
                        connectionStringBuilder.ProviderConnectionString = storeConnectionString; 
                        return connectionStringBuilder.ConnectionString;
                    } 
                } 

                return userConnectionString; 
            }
            set
            {
                ValidateChangesPermitted(); 
                this.ChangeConnectionString(value);
            } 
        } 

        ///  
        /// Formats provider string to replace " with \" so it can be appended within quotation marks "..."
        /// 
        private static string FormatProviderString(string providerString)
        { 
            return providerString.Trim().Replace("\"", "\\\"");
        } 
 
        /// 
        /// Get the time to wait when attempting to establish a connection before ending the try and generating an error 
        /// 
        public override int ConnectionTimeout
        {
            get 
            {
                if (this._storeConnection == null) 
                    return 0; 

                try 
                {
                    return this._storeConnection.ConnectionTimeout;
                }
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    { 
                        throw EntityUtil.Provider(@"ConnectionTimeout", e);
                    } 
                    throw;
                }
            }
        } 

        ///  
        /// Get the name of the current database or the database that will be used after a connection is opened 
        /// 
        public override string Database 
        {
            get
            {
                return String.Empty; 
            }
        } 
 
        /// 
        /// Gets the ConnectionState property of the EntityConnection 
        /// 
        public override ConnectionState State
        {
            get 
            {
                try 
                { 
                    if (this._entityClientConnectionState == ConnectionState.Open)
                    { 
                        Debug.Assert(this.StoreConnection != null);
                        if (this.StoreConnection.State != ConnectionState.Open)
                        {
                            return ConnectionState.Broken; 
                        }
                    } 
                    return this._entityClientConnectionState; 
                }
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e))
                    {
                        throw EntityUtil.Provider(@"State", e); 
                    }
                    throw; 
                } 
            }
        } 

        /// 
        /// Gets the name or network address of the data source to connect to
        ///  
        public override string DataSource
        { 
            get 
            {
                if (this._storeConnection == null) 
                    return String.Empty;

                try
                { 
                    return this._storeConnection.DataSource;
                } 
                catch (Exception e) 
                {
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    {
                        throw EntityUtil.Provider(@"DataSource", e);
                    }
                    throw; 
                }
            } 
        } 

        ///  
        /// Gets a string that contains the version of the data store to which the client is connected
        /// 
        public override string ServerVersion
        { 
            get
            { 
                if (this._storeConnection == null) 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
 
                if (this.State != ConnectionState.Open)
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
                } 

                try 
                { 
                    return this._storeConnection.ServerVersion;
                } 
                catch (Exception e)
                {
                    if (EntityUtil.IsCatchableExceptionType(e))
                    { 
                        throw EntityUtil.Provider(@"ServerVersion", e);
                    } 
                    throw; 
                }
            } 
        }

        /// 
        /// Gets the provider factory associated with EntityConnection 
        /// 
        override protected DbProviderFactory DbProviderFactory 
        { 
            get
            { 
                return EntityProviderFactory.Instance;
            }
        }
 
        /// 
        /// Gets the DbProviderFactory for the underlying provider 
        ///  
        internal DbProviderFactory StoreProviderFactory
        { 
            get
            {
                return this._providerFactory;
            } 
        }
 
        ///  
        /// Gets the DbConnection for the underlying provider connection
        ///  
        public DbConnection StoreConnection
        {
            get
            { 
                return this._storeConnection;
            } 
        } 

        ///  
        /// Gets the metadata workspace used by this connection
        /// 
        public MetadataWorkspace GetMetadataWorkspace()
        { 
            return GetMetadataWorkspace(true /* initializeAllCollections */);
        } 
 
        internal MetadataWorkspace GetMetadataWorkspace(bool initializeAllCollections)
        { 
            Debug.Assert(_metadataWorkspace != null || _effectiveConnectionOptions != null, "The effective connection options is null, which should never be");
            if (_metadataWorkspace == null ||
                (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)))
            { 
                // This lock is to ensure that the connection string and the metadata workspace are in a consistent state, that is, you
                // don't get a metadata workspace not matching what's described by the connection string 
                lock (_connectionStringLock) 
                {
                    EdmItemCollection edmItemCollection = null; 
                    if (_metadataWorkspace == null)
                    {
                        MetadataWorkspace workspace = new MetadataWorkspace();
 
                        _artifactLoader = SplitPaths(_effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName]);
                        edmItemCollection = LoadEdmItemCollection(workspace, _artifactLoader); 
                        _metadataWorkspace = workspace; 
                    }
                    else 
                    {
                        edmItemCollection = (EdmItemCollection)_metadataWorkspace.GetItemCollection(DataSpace.CSpace);
                    }
 
                    if (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
                    { 
                        LoadStoreItemCollections(_metadataWorkspace, _storeConnection, _providerFactory, _effectiveConnectionOptions, edmItemCollection, _artifactLoader); 
                        _artifactLoader = null;
                        _initialized = true; 
                    }
                }
            }
 
            return _metadataWorkspace;
        } 
 
        /// 
        /// Gets the current transaction that this connection is enlisted in 
        /// 
        internal EntityTransaction CurrentTransaction
        {
            get 
            {
                // Null out the current transaction if the state is closed or zombied 
                if ((null != _currentTransaction) && ((null == _currentTransaction.StoreTransaction.Connection) || (this.State == ConnectionState.Closed))) 
                {
                    ClearCurrentTransaction(); 
                }
                return _currentTransaction;
            }
        } 

        ///  
        /// Establish a connection to the data store by calling the Open method on the underlying data provider 
        /// 
        public override void Open() 
        {
            if (this._storeConnection == null)
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
 
            if (this.State != ConnectionState.Closed)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_CannotReopenConnection); 
            }
 
            bool closeStoreConnectionOnFailure = false;
            OpenStoreConnectionIf(this._storeConnection.State != ConnectionState.Open,
                                  this._storeConnection,
                                  null, 
                                  EntityRes.EntityClient_ProviderSpecificError,
                                  @"Open", 
                                  ref closeStoreConnectionOnFailure); 

            // the following guards against the case when the user closes the underlying store connection 
            // in the state change event handler, as a consequence of which we are in the 'Broken' state
            if (this._storeConnection == null || this._storeConnection.State != ConnectionState.Open)
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen); 
            }
 
            InitializeMetadata(this._storeConnection, this._storeConnection, closeStoreConnectionOnFailure); 
            SetEntityClientConnectionStateToOpen();
        } 

        /// 
        /// Helper method that conditionally opens a specified store connection
        ///  
        /// The condition to evaluate
        /// The store connection to open 
        /// The original store connection associated with the entity client 
        /// A flag that is set on if the connection is opened
        /// successfully 
        private void OpenStoreConnectionIf(bool openCondition,
                                           DbConnection storeConnectionToOpen,
                                           DbConnection originalConnection,
                                           string exceptionCode, 
                                           string attemptedOperation,
                                           ref bool closeStoreConnectionOnFailure) 
        { 
            try
            { 
                if (openCondition)
                {
                    storeConnectionToOpen.Open();
                    closeStoreConnectionOnFailure = true; 
                }
 
                ResetStoreConnection(storeConnectionToOpen, originalConnection, false); 

                // With every successful open of the store connection, always null out the current 
                // transaction (if there is one)
                ClearCurrentTransaction();
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    string exceptionMessage = string.IsNullOrEmpty(attemptedOperation) ?
                        EntityRes.GetString(exceptionCode) : 
                        EntityRes.GetString(exceptionCode, attemptedOperation);

                    throw EntityUtil.ProviderExceptionWithMessage(exceptionMessage, e);
                } 
                throw;
            } 
        } 

        ///  
        /// Helper method to initialize the metadata workspace and reset the store connection
        /// associated with the entity client
        /// 
        /// The new connection to associate with the entity client 
        /// The original connection associated with the entity client
        /// A flag to indicate whether the original 
        /// store connection needs to be closed on failure 
        private void InitializeMetadata(DbConnection newConnection,
                                        DbConnection originalConnection, 
                                        bool closeOriginalConnectionOnFailure)
        {
            try
            { 
                // Ensure metadata is loaded and the workspace is appropriately initialized.
                GetMetadataWorkspace(); 
            } 
            catch (Exception ex)
            { 
                // Undo the open if something failed
                if (EntityUtil.IsCatchableExceptionType(ex))
                {
                    ResetStoreConnection(newConnection, originalConnection, closeOriginalConnectionOnFailure); 
                }
                throw; 
            } 
        }
 
        /// 
        /// Set the entity client connection state to Open, and raise an appropriate event
        /// 
        private void SetEntityClientConnectionStateToOpen() 
        {
            this._entityClientConnectionState = ConnectionState.Open; 
            OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeOpen); 
        }
 
        /// 
        /// This method sets the store connection and hooks up the event
        /// 
        /// The  DbConnection to set 
        /// The original DbConnection to be closed - this argument could be null
        /// Indicates whether the original store connection should be closed 
        private void ResetStoreConnection(DbConnection newConnection, DbConnection originalConnection, bool closeOriginalConnection) 
        {
            this._storeConnection = newConnection; 

            if (closeOriginalConnection && (originalConnection != null))
            {
                originalConnection.Close(); 
            }
        } 
 
        /// 
        /// Create a new command object that uses this connection object 
        /// 
        public new EntityCommand CreateCommand()
        {
            return new EntityCommand(null, this); 
        }
 
        ///  
        /// Create a new command object that uses this connection object
        ///  
        protected override DbCommand CreateDbCommand()
        {
            return this.CreateCommand();
        } 

        internal EntityConnection Clone() 
        { 
            return new EntityConnection(_userConnectionOptions.UsersConnectionString(false));
        } 

        /// 
        /// Close the connection to the data store
        ///  
        public override void Close()
        { 
            // It's a no-op if there isn't an underlying connection 
            if (this._storeConnection == null)
                return; 

            this.CloseHelper();
        }
 
        /// 
        /// Changes the current database for this connection 
        ///  
        /// The name of the database to change to
        public override void ChangeDatabase(string databaseName) 
        {
            throw EntityUtil.NotSupported();
        }
 
        /// 
        /// Begins a database transaction 
        ///  
        /// An object representing the new transaction
        public new EntityTransaction BeginTransaction() 
        {
            return base.BeginTransaction() as EntityTransaction;
        }
 
        /// 
        /// Begins a database transaction 
        ///  
        /// The isolation level of the transaction
        /// An object representing the new transaction 
        public new EntityTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            return base.BeginTransaction(isolationLevel) as EntityTransaction;
        } 

        ///  
        /// Begins a database transaction 
        /// 
        /// The isolation level of the transaction 
        /// An object representing the new transaction
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            if (CurrentTransaction != null) 
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_TransactionAlreadyStarted); 
            } 

            if (this._storeConnection == null) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);

            if (this.State != ConnectionState.Open)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
            } 
 
            DbTransaction storeTransaction = null;
            try 
            {
                storeTransaction = this._storeConnection.BeginTransaction(isolationLevel);
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    throw EntityUtil.ProviderExceptionWithMessage(
                                            System.Data.Entity.Strings.EntityClient_ErrorInBeginningTransaction, 
                                            e
                                        );
                }
                throw; 
            }
 
            // The provider is problematic if it succeeded in beginning a transaction but returned a null 
            // for the transaction object
            if (storeTransaction == null) 
            {
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("BeginTransaction", _storeConnection.GetType().Name));
            }
 
            _currentTransaction = new EntityTransaction(this, storeTransaction);
            return _currentTransaction; 
        } 

        ///  
        /// Enlist in the given transaction
        /// 
        /// The transaction object to enlist into
        public override void EnlistTransaction(Transaction transaction) 
        {
            if (_storeConnection == null) 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation); 

            if (this.State != ConnectionState.Open) 
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
            }
 
            try
            { 
                _storeConnection.EnlistTransaction(transaction); 
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e))
                {
                    throw EntityUtil.Provider(@"EnlistTransaction", e); 
                }
                throw; 
            } 
        }
 
        /// 
        /// Cleans up this connection object
        /// 
        /// true to release both managed and unmanaged resources; false to release only unmanaged resources 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_currentTransaction")]
        protected override void Dispose(bool disposing) 
        { 
            ClearCurrentTransaction();
            bool raiseStateChangeEvent = EntityCloseHelper(false, this.State); 

            if (disposing)
            {
                if (this._storeConnection != null) 
                {
                    StoreCloseHelper(); // closes store connection 
                    if (this._storeConnection != null) 
                    {
                        this._storeConnection.Dispose(); 
                        this._storeConnection = null;
                    }
                }
            } 

            // Change the connection string to just an empty string, ChangeConnectionString should always succeed here, 
            // it's unnecessary to pass in the connection string parameter name in the second argument, which we don't 
            // have anyway
            this.ChangeConnectionString(String.Empty); 

            if (raiseStateChangeEvent)  // we need to raise the event explicitly
            {
                OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed); 
            }
 
            base.Dispose(disposing); 
        }
 
        /// 
        /// Reinitialize this connection object to use the new connection string
        /// 
        /// The new connection string 
        private void ChangeConnectionString(string newConnectionString)
        { 
            DbConnectionOptions userConnectionOptions = s_emptyConnectionOptions; 
            if (!String.IsNullOrEmpty(newConnectionString))
            { 
                userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.Synonyms, false);
            }

            DbProviderFactory factory = null; 
            DbConnection storeConnection = null;
            DbConnectionOptions effectiveConnectionOptions = userConnectionOptions; 
 
            if (!userConnectionOptions.IsEmpty)
            { 
                // Check if we have the named connection, if yes, then use the connection string from the configuration manager settings
                string namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
                if (!string.IsNullOrEmpty(namedConnection))
                { 
                    // There cannot be other parameters when the named connection is specified
                    if (1 < userConnectionOptions.Parsetable.Count) 
                    { 
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ExtraParametersWithNamedConnection);
                    } 

                    // Find the named connection from the configuration, then extract the settings
                    ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[namedConnection];
                    if (setting == null || setting.ProviderName != EntityConnection.s_entityClientProviderName) 
                    {
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidNamedConnection); 
                    } 

                    effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms, false); 

                    // Check for a nested Name keyword
                    string nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
                    if (!string.IsNullOrEmpty(nestedNamedConnection)) 
                    {
                        throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_NestedNamedConnection(namedConnection)); 
                    } 
                }
 
                //Validate the connection string has the required Keywords( Provider and Metadata)
                //We trim the values for both the Keywords, so a string value with only spaces will throw an exception
                //reporting back to the user that the Keyword was missing.
                ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName); 

                string providerName = ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName); 
                // Get the correct provider factory 
                factory = GetFactory(providerName);
 
                // Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object
                storeConnection = GetStoreConnection(factory);

                try 
                {
                    // When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all. 
                    // Providers should still be able handle empty connection strings since those may be explicitly passed by clients. 
                    string providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
                    if (providerConnectionString != null) 
                    {
                        storeConnection.ConnectionString = providerConnectionString;
                    }
                } 
                catch (Exception e)
                { 
                    if (EntityUtil.IsCatchableExceptionType(e)) 
                    {
                        throw EntityUtil.Provider(@"ConnectionString", e); 
                    }
                    throw;
                }
            } 

            // This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being 
            // managed by this EntityConnection, so states in this connection object are not messed up. 
            // It's not for security, but just to help reduce user error.
            lock (_connectionStringLock) 
            {
                // Now we have sufficient information and verified the configuration string is good, use them for this connection object
                // Failure should not occur from this point to the end of this method
                this._providerFactory = factory; 
                this._metadataWorkspace = null;
 
                ClearCurrentTransaction(); 

                ResetStoreConnection(storeConnection, null, false); 

                // Remembers the connection options objects with the connection string set by the user
                this._userConnectionOptions = userConnectionOptions;
                this._effectiveConnectionOptions = effectiveConnectionOptions; 
            }
        } 
 
        private static string ValidateValueForTheKeyword(DbConnectionOptions effectiveConnectionOptions,
            string keywordName) 
        {
            string keywordValue = effectiveConnectionOptions[keywordName];
            if (!string.IsNullOrEmpty(keywordValue))
                keywordValue = keywordValue.Trim(); // be nice to user, always trim the value 

            // Check that we have a non-null and non-empty value for the keyword 
            if (string.IsNullOrEmpty(keywordValue)) 
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionStringMissingInfo(keywordName)); 
            }
            return keywordValue;
        }
 
        private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspace, MetadataArtifactLoader artifactLoader)
        { 
            // Build a string as the key and look up the MetadataCache for a match 
            string edmCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
 
            // Check the MetadataCache for an entry with this key
            object entryToken;
            EdmItemCollection edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(edmCacheKey,
                                                                                        artifactLoader, 
                                                                                        out entryToken);
            workspace.RegisterItemCollection(edmItemCollection); 
 
            // Adding the edm metadata entry token to the workspace, to make sure that this token remains alive till workspace is alive
            workspace.AddMetadataEntryToken(entryToken); 

            return edmItemCollection;
        }
 
        private static void LoadStoreItemCollections(MetadataWorkspace workspace,
                                                     DbConnection storeConnection, 
                                                     DbProviderFactory factory, 
                                                     DbConnectionOptions connectionOptions,
                                                     EdmItemCollection edmItemCollection, 
                                                     MetadataArtifactLoader artifactLoader)
        {
            Debug.Assert(workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space");
 
            // The provider connection string is optional; if it has not been specified,
            // we pick up the store's connection string. 
            // 
            string providerConnectionString = connectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
            if (string.IsNullOrEmpty(providerConnectionString) && (storeConnection != null)) 
            {
                providerConnectionString = storeConnection.ConnectionString;
            }
 
            // Build a string as the key and look up the MetadataCache for a match
            string storeCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(), 
                                                          connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], 
                                                          providerConnectionString);
 
            // Load store metadata.
            object entryToken;
            StorageMappingItemCollection mappingCollection =
                MetadataCache.GetOrCreateStoreAndMappingItemCollections(storeCacheKey, 
                                                                     artifactLoader,
                                                                     edmItemCollection, 
                                                                     out entryToken); 

            ValidateThatConnectionAndMetadataProvidersAreEqual(factory, connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], mappingCollection.StoreItemCollection.StoreProviderFactory); 
            workspace.RegisterItemCollection(mappingCollection.StoreItemCollection);
            workspace.RegisterItemCollection(mappingCollection);

            // Adding the store metadata entry token to the workspace 
            workspace.AddMetadataEntryToken(entryToken);
        } 
 
        private static void ValidateThatConnectionAndMetadataProvidersAreEqual(DbProviderFactory connectionFactory, string connectionProviderName, DbProviderFactory metadataFactory)
        { 
            if (metadataFactory.GetType() != connectionFactory.GetType())
            {
                string metadataProviderName = GetErrorMessageWorthyProviderName(metadataFactory);
 
                if (string.IsNullOrEmpty(connectionProviderName))
                { 
                    connectionProviderName = GetErrorMessageWorthyProviderName(connectionFactory); 
                }
 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionAndMetadataProviderMismatch(metadataProviderName, connectionProviderName));
            }
        }
 
        private static string GetErrorMessageWorthyProviderName(DbProviderFactory factory)
        { 
            EntityUtil.CheckArgumentNull(factory, "factory"); 

            string providerName; 
            if (!EntityUtil.TryGetProviderInvariantName(factory, out providerName))
            {
                providerName = factory.GetType().FullName;
            } 
            return providerName;
        } 
 
        /// 
        /// Create a key to be used with the MetadataCache from a connection options object 
        /// 
        /// A list of metadata file paths
        /// The provider name
        /// The provider connection string 
        /// The key
        private static string CreateMetadataCacheKey(IList paths, string providerName, string providerConnectionString) 
        { 
            int resultCount = 0;
            string result; 

            // Do a first pass to calculate the output size of the metadata cache key,
            // then another pass to populate a StringBuilder with the exact size and
            // get the result. 
            CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
                false, ref resultCount, out result); 
            CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString, 
                true, ref resultCount, out result);
 
            return result;
        }

        ///  
        /// Create a key to be used with the MetadataCache from a connection options
        /// object. 
        ///  
        /// A list of metadata file paths
        /// The provider name 
        /// The provider connection string
        /// Whether the result variable should be built.
        /// 
        /// On entry, the expected size of the result (unused if buildResult is false). 
        /// After execution, the effective result.
        /// The key. 
        ///  
        /// This method should be called once with buildResult=false, to get
        /// the size of the resulting key, and once with buildResult=true 
        /// and the size specification.
        /// 
        private static void CreateMetadataCacheKeyWithCount(IList paths,
            string providerName, string providerConnectionString, 
            bool buildResult, ref int resultCount, out string result)
        { 
            // Build a string as the key and look up the MetadataCache for a match 
            StringBuilder keyString;
            if (buildResult) 
            {
                keyString = new StringBuilder(resultCount);
            }
            else 
            {
                keyString = null; 
            } 

            // At this point, we've already used resultCount. Reset it 
            // to zero to make the final debug assertion that our computation
            // is correct.
            resultCount = 0;
 
            if (!string.IsNullOrEmpty(providerName))
            { 
                resultCount += providerName.Length + 1; 
                if (buildResult)
                { 
                    keyString.Append(providerName);
                    keyString.Append(EntityConnection.s_semicolonSeparator);
                }
            } 

            if (paths != null) 
            { 
                for (int i = 0; i < paths.Count; i++)
                { 
                    if (paths[i].Length > 0)
                    {
                        if (i > 0)
                        { 
                            resultCount++;
                            if (buildResult) 
                            { 
                                keyString.Append(EntityConnection.s_metadataPathSeparator);
                            } 
                        }
                        resultCount += paths[i].Length;
                        if (buildResult)
                        { 
                            keyString.Append(paths[i]);
                        } 
                    } 
                }
                resultCount++; 
                if (buildResult)
                {
                    keyString.Append(EntityConnection.s_semicolonSeparator);
                } 
            }
 
            if (!string.IsNullOrEmpty(providerConnectionString)) 
            {
                resultCount += providerConnectionString.Length; 
                if (buildResult)
                {
                    keyString.Append(providerConnectionString);
                } 
            }
 
            if (buildResult) 
            {
                result = keyString.ToString(); 
            }
            else
            {
                result = null; 
            }
 
            System.Diagnostics.Debug.Assert( 
                !buildResult || (result.Length == resultCount));
        } 

        /// 
        /// A helper function for splitting up a string that is a concatenation of strings delimited by the metadata
        /// path separator into a string list. The resulting list is NOT sorted. 
        /// 
        /// The paths to split 
        /// An array of strings 
        private static MetadataArtifactLoader SplitPaths(string paths)
        { 
            string[] results;

            // This is the registry of all URIs in the global collection.
            HashSet uriRegistry = new HashSet(StringComparer.OrdinalIgnoreCase); 

            List loaders = new List(); 
 
            if (!string.IsNullOrEmpty(paths))
            { 
                // If the argument contains one or more occurrences of the macro '|DataDirectory|', we
                // pull those paths out so that we don't lose them in the string-splitting logic below.
                // Note that the macro '|DataDirectory|' cannot have any whitespace between the pipe
                // symbols and the macro name. Also note that the macro must appear at the beginning of 
                // a path (else we will eventually fail with an invalid path exception, because in that
                // case the macro is not expanded). If a real/physical folder named 'DataDirectory' needs 
                // to be included in the metadata path, whitespace should be used on either or both sides 
                // of the name.
                // 
                List dataDirPaths = new List();

                int indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
                while (indexStart != -1) 
                {
                    int prevSeparatorIndex = indexStart == 0 ? -1 : paths.LastIndexOf( 
                                                                    EntityConnection.s_metadataPathSeparator, 
                                                                    indexStart - 1, // start looking here
                                                                    StringComparison.Ordinal 
                                                                );

                    int macroPathBeginIndex = prevSeparatorIndex + 1;
 
                    // The '|DataDirectory|' macro is composable, so identify the complete path, like
                    // '|DataDirectory|\foo\bar'. If the macro appears anywhere other than at the 
                    // beginning, splice out the entire path, e.g. 'C:\foo\|DataDirectory|\bar'. In this 
                    // latter case the macro will not be expanded, and downstream code will throw an exception.
                    // 
                    int indexEnd = paths.IndexOf(EntityConnection.s_metadataPathSeparator,
                                                 indexStart + EntityConnection.s_dataDirectory.Length,
                                                 StringComparison.Ordinal);
                    if (indexEnd == -1) 
                    {
                        dataDirPaths.Add(paths.Substring(macroPathBeginIndex)); 
                        paths = paths.Remove(macroPathBeginIndex);   // update the concatenated list of paths 
                        break;
                    } 

                    dataDirPaths.Add(paths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex));

                    // Update the concatenated list of paths by removing the one containing the macro. 
                    //
                    paths = paths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex); 
                    indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase); 
                }
 
                // Split the string on the separator and remove all spaces around each parameter value
                results = paths.Split(new string[] { EntityConnection.s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries);

                // Now that the non-macro paths have been identified, merge the paths containing the macro 
                // into the complete list.
                // 
                if (dataDirPaths.Count > 0) 
                {
                    dataDirPaths.AddRange(results); 
                    results = dataDirPaths.ToArray();
                }

                for (int i = 0; i < results.Length; i++) 
                {
                    // Trim out all the spaces for this parameter and add it only if it's not blank 
                    results[i] = results[i].Trim(); 
                    if (results[i].Length > 0)
                    { 
                        loaders.Add(MetadataArtifactLoader.Create(
                                        results[i],
                                        MetadataArtifactLoader.ExtensionCheck.All,  // validate the extension against all acceptable values
                                        null, 
                                        uriRegistry
                                    )); 
                    } 
                }
            } 

            return MetadataArtifactLoader.Create(loaders);
        }
 
        /// 
        /// Clears the current transaction for this connection 
        ///  
        internal void ClearCurrentTransaction()
        { 
            _currentTransaction = null;
        }

        ///  
        /// Helper method invoked as part of Close()/Dispose() that releases the underlying
        /// store connection and raises the appropriate event. 
        ///  
        private void CloseHelper()
        { 
            ConnectionState previousState = this.State; // the public connection state before cleanup
            StoreCloseHelper();
            EntityCloseHelper(
                            true,   // raise the state change event 
                            previousState
                        ); 
        } 

        ///  
        /// Store-specific helper method invoked as part of Close()/Dispose().
        /// 
        private void StoreCloseHelper()
        { 
            try
            { 
                if (this._storeConnection != null && (this._storeConnection.State != ConnectionState.Closed)) 
                {
                    this._storeConnection.Close(); 
                }
                // Need to disassociate the transaction object with this connection
                ClearCurrentTransaction();
            } 
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e)) 
                {
                    throw EntityUtil.ProviderExceptionWithMessage( 
                                        System.Data.Entity.Strings.EntityClient_ErrorInClosingConnection,
                                        e
                                    );
                } 
                throw;
            } 
        } 

        ///  
        /// Entity-specific helper method invoked as part of Close()/Dispose().
        /// 
        /// Indicates whether we need to raise the state change event here
        /// The public state of the connection before cleanup began 
        /// true if the caller needs to raise the state change event
        private bool EntityCloseHelper(bool fireEventOnStateChange, ConnectionState previousState) 
        { 
            bool result = false;
 
            this._entityClientConnectionState = ConnectionState.Closed;

            if (previousState == ConnectionState.Open)
            { 
                if (fireEventOnStateChange)
                { 
                    OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed); 
                }
                else 
                {
                    result = true;  // we didn't raise the event here; the caller should do that
                }
            } 

            return result; 
        } 

        ///  
        /// Call to determine if changes to the entity object are currently permitted.
        /// 
        private void ValidateChangesPermitted()
        { 
            if (_initialized)
            { 
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_SettingsCannotBeChangedOnOpenConnection); 
            }
        } 

        /// 
        /// Returns the DbProviderFactory associated with specified provider string
        ///  
        private DbProviderFactory GetFactory(string providerString)
        { 
            try 
            {
                return DbProviderFactories.GetFactory(providerString); 
            }
            catch (ArgumentException e)
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidStoreProvider, e); 
            }
        } 
 
        /// 
        /// Uses DbProviderFactory to create a DbConnection 
        /// 
        private DbConnection GetStoreConnection(DbProviderFactory factory)
        {
            DbConnection storeConnection = factory.CreateConnection(); 
            if (storeConnection == null)
            { 
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("CreateConnection", factory.GetType().Name)); 
            }
            return storeConnection; 
        }

    }
} 

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

                        

Link Menu

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