Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / EntityClient / EntityConnection.cs / 1305376 / EntityConnection.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.Common; using System.Data.Common.EntitySql; using System.Data.Mapping; using System.Data.Metadata; using System.Data.Metadata.Edm; using System.Diagnostics; using System.IO; using System.Text; using System.Transactions; using System.Xml; using System.Data.Common.CommandTrees; using System.Runtime.Versioning; using System.Linq; namespace System.Data.EntityClient { ////// 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_providerInvariantName = "provider"; private const string s_providerConnectionString = "provider connection string"; private const string s_readerPrefix = "reader://"; #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 readonly bool _userOwnsStoreConnection; private MetadataWorkspace _metadataWorkspace; private EntityTransaction _currentTransaction; 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 /// [ResourceExposure(ResourceScope.None)] //We are not exposing any resource [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //For EntityConnection constructor. But since the connection string we pass in is an Empty String, //we consume the resource and do not expose it any further. 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 [ResourceExposure(ResourceScope.Machine)] //Exposes the file names as part of ConnectionString which are a Machine resource [ResourceConsumption(ResourceScope.Machine)] //For ChangeConnectionString method call. But the paths are not created in this method. 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); GC.SuppressFinalize(this); _providerFactory = collection.StoreProviderFactory; _storeConnection = connection; _userOwnsStoreConnection = true; _metadataWorkspace = workspace; _initialized = true; } ////// 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}{4};{1}={5};{2}=\"{6}\";", EntityConnectionStringBuilder.MetadataParameterName, s_providerInvariantName, s_providerConnectionString, s_readerPrefix, _metadataWorkspace.MetadataWorkspaceId, 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; } [ResourceExposure(ResourceScope.Machine)] //Exposes the file names as part of ConnectionString which are a Machine resource [ResourceConsumption(ResourceScope.Machine)] //For ChangeConnectionString method call. But the paths are not created in this method. 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 /// [CLSCompliant(false)] public MetadataWorkspace GetMetadataWorkspace() { return GetMetadataWorkspace(true /* initializeAllCollections */); } private bool ShouldRecalculateMetadataArtifactLoader(Listloaders) { if (loaders.Any(loader => loader.GetType() == typeof(MetadataArtifactLoaderCompositeFile))) { // the loaders had folders in it return true; } // in the case that loaders only contains resources or file name, we trust the cache return false; } [ResourceExposure(ResourceScope.None)] //The resource( path name) is not exposed to the callers of this method [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //Fir SplitPaths call and we pick the file names from class variable. 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(); List loaders = new List (); string paths = _effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName]; if (!string.IsNullOrEmpty(paths)) { loaders = MetadataCache.GetOrCreateMetdataArtifactLoader(paths); if(!ShouldRecalculateMetadataArtifactLoader(loaders)) { _artifactLoader = MetadataArtifactLoader.Create(loaders); } else { // the loaders contains folders that might get updated during runtime, so we have to recalculate the loaders again _artifactLoader = MetadataArtifactLoader.Create(MetadataCache.SplitPaths(paths)); } } else { _artifactLoader = MetadataArtifactLoader.Create(loaders); } 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(); } ////// 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")] [ResourceExposure(ResourceScope.None)] //We are not exposing any resource [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //For ChangeConnectionString method call. But since the connection string we pass in is an Empty String, //we consume the resource and do not expose it any further. 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) { if (!this._userOwnsStoreConnection) // only dispose it if we didn't get it from the user... { 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 [ResourceExposure(ResourceScope.Machine)] //Exposes the file names which are a Machine resource as part of the 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); workspace.RegisterItemCollection(mappingCollection.StoreItemCollection); workspace.RegisterItemCollection(mappingCollection); // Adding the store metadata entry token to the workspace workspace.AddMetadataEntryToken(entryToken); } 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(IListpaths, 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(IListpaths, 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)); } /// /// 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ComContractElement.cs
- AttachedPropertyBrowsableAttribute.cs
- arclist.cs
- StubHelpers.cs
- PackageFilter.cs
- CompareInfo.cs
- Trace.cs
- SplitterDesigner.cs
- ListBoxAutomationPeer.cs
- TypeConverterHelper.cs
- XmlAttributeProperties.cs
- dbenumerator.cs
- EncryptedType.cs
- ArcSegment.cs
- SqlDuplicator.cs
- ContentFilePart.cs
- PartialClassGenerationTask.cs
- Util.cs
- OneOfConst.cs
- CheckBoxRenderer.cs
- CodeParameterDeclarationExpression.cs
- HScrollProperties.cs
- FixedDocumentPaginator.cs
- PtsPage.cs
- Odbc32.cs
- DataGridViewDataConnection.cs
- TypeDelegator.cs
- SHA1.cs
- RC2.cs
- PlainXmlSerializer.cs
- CultureTable.cs
- RegisteredHiddenField.cs
- FileChangesMonitor.cs
- DataGridViewDataErrorEventArgs.cs
- TextOptions.cs
- dataprotectionpermission.cs
- ProfileInfo.cs
- RadioButtonStandardAdapter.cs
- SqlCommandSet.cs
- ScrollBarRenderer.cs
- NativeMethods.cs
- ClientRolePrincipal.cs
- Operand.cs
- ExternalException.cs
- WizardPanelChangingEventArgs.cs
- GeneralTransformGroup.cs
- OutOfMemoryException.cs
- SimpleHandlerFactory.cs
- XmlNotation.cs
- OleDbTransaction.cs
- LogLogRecordHeader.cs
- ResolveCriteria11.cs
- DriveNotFoundException.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- ConfigXmlText.cs
- SqlClientFactory.cs
- DataServiceProviderMethods.cs
- StreamUpgradeInitiator.cs
- CombinedGeometry.cs
- HtmlInputImage.cs
- WebPartConnectionsConfigureVerb.cs
- basemetadatamappingvisitor.cs
- brushes.cs
- BitmapEffectGroup.cs
- TextServicesContext.cs
- EditorOptionAttribute.cs
- EventLogPermissionEntryCollection.cs
- UnsafeNativeMethods.cs
- XmlReaderSettings.cs
- VirtualPath.cs
- ImageField.cs
- MeasurementDCInfo.cs
- AttributeTable.cs
- DataPagerCommandEventArgs.cs
- DataFieldEditor.cs
- EqualityComparer.cs
- ExpressionPrefixAttribute.cs
- XmlSchemaComplexType.cs
- HtmlElementErrorEventArgs.cs
- ExtenderHelpers.cs
- Stack.cs
- Font.cs
- EditorBrowsableAttribute.cs
- TrackingCondition.cs
- StringInfo.cs
- NegationPusher.cs
- GuidConverter.cs
- CustomWebEventKey.cs
- Interlocked.cs
- BindingCollection.cs
- GradientStop.cs
- StatusBarPanelClickEvent.cs
- BrowserCapabilitiesCompiler.cs
- DelegatingHeader.cs
- WindowsListViewGroup.cs
- DbModificationCommandTree.cs
- AsyncDataRequest.cs
- ProxyGenerationError.cs
- SqlExpressionNullability.cs
- String.cs