protected override string GetDbProviderManifestToken(DbConnection connection) { EntityUtil.CheckArgumentNull(connection, "connection"); SqlConnection sqlConnection = SqlProviderUtilities.GetRequiredSqlConnection(connection); if (string.IsNullOrEmpty(sqlConnection.ConnectionString)) { throw EntityUtil.Argument(Strings.UnableToDetermineStoreVersion); } string providerManifestToken = null; // Try to get the provider manifest token from the database connection // That failing, try using connection to master database (in case the database doesn't exist yet) try { UsingConnection(sqlConnection, conn => { providerManifestToken = SqlVersionUtils.GetVersionHint(SqlVersionUtils.GetSqlVersion(conn)); }); } catch { UsingMasterConnection(sqlConnection, conn => { providerManifestToken = SqlVersionUtils.GetVersionHint(SqlVersionUtils.GetSqlVersion(conn)); }); } return(providerManifestToken); }
/// <summary> /// Create the database and the database objects. /// If initial catalog is not specified, but AttachDBFilename is specified, we generate a random database name based on the AttachDBFilename. /// Note: this causes pollution of the db, as when the connection string is later used, the mdf will get attached under a different name. /// However if we try to replicate the name under which it would be attached, the following scenario would fail: /// The file does not exist, but registered with database. /// The user calls: If (DatabaseExists) DeleteDatabase /// CreateDatabase /// For further details on the behavior when AttachDBFilename is specified see Dev10# 188936 /// </summary> protected override void DbCreateDatabase(DbConnection connection, int?commandTimeout, StoreItemCollection storeItemCollection) { EntityUtil.CheckArgumentNull(connection, "connection"); EntityUtil.CheckArgumentNull(storeItemCollection, "storeItemCollection"); SqlConnection sqlConnection = SqlProviderUtilities.GetRequiredSqlConnection(connection); string databaseName, dataFileName, logFileName; GetOrGenerateDatabaseNameAndGetFileNames(sqlConnection, out databaseName, out dataFileName, out logFileName); string createDatabaseScript = SqlDdlBuilder.CreateDatabaseScript(databaseName, dataFileName, logFileName); SqlVersion sqlVersion = GetSqlVersion(storeItemCollection); string createObjectsScript = CreateObjectsScript(sqlVersion, storeItemCollection); UsingMasterConnection(sqlConnection, conn => { // create database CreateCommand(conn, createDatabaseScript, commandTimeout).ExecuteNonQuery(); }); // Create database already succeeded. If there is a failure from this point on, the user should be informed. try { // Clear connection pool for the database connection since after the 'create database' call, a previously // invalid connection may now be valid. SqlConnection.ClearPool(sqlConnection); UsingConnection(sqlConnection, conn => { // create database objects CreateCommand(conn, createObjectsScript, commandTimeout).ExecuteNonQuery(); }); } catch (Exception e) { if (EntityUtil.IsCatchableExceptionType(e)) { // Try to drop the database try { DropDatabase(sqlConnection, commandTimeout, databaseName); } catch (Exception ie) { // The creation of the database succeeded, the creation of the database objects failed, and the dropping of the database failed. if (EntityUtil.IsCatchableExceptionType(ie)) { throw new InvalidOperationException(Strings.SqlProvider_IncompleteCreateDatabase, new AggregateException(Strings.SqlProvider_IncompleteCreateDatabaseAggregate, e, ie)); } throw; } // The creation of the database succeeded, the creation of the database objects failed, the database was dropped, no reason to wrap the exception throw; } throw; } }
/// <summary> /// Determines whether the database for the given connection exists. /// There are three cases: /// 1. Initial Catalog = X, AttachDBFilename = null: (SELECT Count(*) FROM sys.databases WHERE [name]= X) > 0 /// 2. Initial Catalog = X, AttachDBFilename = F: if (SELECT Count(*) FROM sys.databases WHERE [name]= X) > true, /// if not, try to open the connection and then return (SELECT Count(*) FROM sys.databases WHERE [name]= X) > 0 /// 3. Initial Catalog = null, AttachDBFilename = F: Try to open the connection. If that succeeds the result is true, otherwise /// if the there are no databases corresponding to the given file return false, otherwise throw. /// /// Note: We open the connection to cover the scenario when the mdf exists, but is not attached. /// Given that opening the connection would auto-attach it, it would not be appropriate to return false in this case. /// Also note that checking for the existence of the file does not work for a remote server. (Dev11 #290487) /// For further details on the behavior when AttachDBFilename is specified see Dev10# 188936 /// </summary> protected override bool DbDatabaseExists(DbConnection connection, int?commandTimeout, StoreItemCollection storeItemCollection) { EntityUtil.CheckArgumentNull(connection, "connection"); EntityUtil.CheckArgumentNull(storeItemCollection, "storeItemCollection"); SqlConnection sqlConnection = SqlProviderUtilities.GetRequiredSqlConnection(connection); var connectionBuilder = new SqlConnectionStringBuilder(sqlConnection.ConnectionString); if (string.IsNullOrEmpty(connectionBuilder.InitialCatalog) && string.IsNullOrEmpty(connectionBuilder.AttachDBFilename)) { throw EntityUtil.InvalidOperation(Strings.SqlProvider_DdlGeneration_MissingInitialCatalog); } if (!string.IsNullOrEmpty(connectionBuilder.InitialCatalog)) { if (CheckDatabaseExists(sqlConnection, commandTimeout, connectionBuilder.InitialCatalog)) { //Avoid further processing return(true); } } if (!string.IsNullOrEmpty(connectionBuilder.AttachDBFilename)) { try { UsingConnection(sqlConnection, (SqlConnection con) => { }); return(true); } catch (SqlException e) { if (!string.IsNullOrEmpty(connectionBuilder.InitialCatalog)) { return(CheckDatabaseExists(sqlConnection, commandTimeout, connectionBuilder.InitialCatalog)); } // Initial catalog not specified string fileName = GetMdfFileName(connectionBuilder.AttachDBFilename); bool databaseDoesNotExistInSysTables = false; UsingMasterConnection(sqlConnection, conn => { SqlVersion sqlVersion = SqlVersionUtils.GetSqlVersion(conn); string databaseExistsScript = SqlDdlBuilder.CreateCountDatabasesBasedOnFileNameScript(fileName, useDeprecatedSystemTable: sqlVersion == SqlVersion.Sql8); int result = (int)CreateCommand(conn, databaseExistsScript, commandTimeout).ExecuteScalar(); databaseDoesNotExistInSysTables = (result == 0); }); if (databaseDoesNotExistInSysTables) { return(false); } throw EntityUtil.InvalidOperation(Strings.SqlProvider_DdlGeneration_CannotTellIfDatabaseExists, e); } } // CheckDatabaseExists returned false and no AttachDBFilename is specified return(false); }
/// <summary> /// Delete the database for the given connection. /// There are three cases: /// 1. If Initial Catalog is specified (X) drop database X /// 2. Else if AttachDBFilename is specified (F) drop all the databases corresponding to F /// if none throw /// 3. If niether the catalog not the file name is specified - throw /// /// Note that directly deleting the files does not work for a remote server. However, even for not attached /// databases the current logic would work assuming the user does: if (DatabaseExists) DeleteDatabase /// </summary> /// <param name="connection"></param> /// <param name="commandTimeout"></param> /// <param name="storeItemCollection"></param> protected override void DbDeleteDatabase(DbConnection connection, int?commandTimeout, StoreItemCollection storeItemCollection) { EntityUtil.CheckArgumentNull(connection, "connection"); EntityUtil.CheckArgumentNull(storeItemCollection, "storeItemCollection"); SqlConnection sqlConnection = SqlProviderUtilities.GetRequiredSqlConnection(connection); var connectionBuilder = new SqlConnectionStringBuilder(sqlConnection.ConnectionString); string initialCatalog = connectionBuilder.InitialCatalog; string attachDBFile = connectionBuilder.AttachDBFilename; if (!string.IsNullOrEmpty(initialCatalog)) { DropDatabase(sqlConnection, commandTimeout, initialCatalog); } // initial catalog not specified else if (!string.IsNullOrEmpty(attachDBFile)) { string fullFileName = GetMdfFileName(attachDBFile); List <string> databaseNames = new List <string>(); UsingMasterConnection(sqlConnection, conn => { SqlVersion sqlVersion = SqlVersionUtils.GetSqlVersion(conn); string getDatabaseNamesScript = SqlDdlBuilder.CreateGetDatabaseNamesBasedOnFileNameScript(fullFileName, sqlVersion == SqlVersion.Sql8); var command = CreateCommand(conn, getDatabaseNamesScript, commandTimeout); using (var reader = command.ExecuteReader()) { while (reader.Read()) { databaseNames.Add(reader.GetString(0)); } } }); if (databaseNames.Count > 0) { foreach (var databaseName in databaseNames) { DropDatabase(sqlConnection, commandTimeout, databaseName); } } else { throw EntityUtil.InvalidOperation(Strings.SqlProvider_DdlGeneration_CannotDeleteDatabaseNoInitialCatalog); } } // neither initial catalog nor attachDB file name are specified else { throw EntityUtil.InvalidOperation(Strings.SqlProvider_DdlGeneration_MissingInitialCatalog); } }