2010-02-09 31 views
29

Questo sembra piuttosto banale, ma ora mi sta frustrando.Verifica se il database esiste prima della creazione

Sto usando C# con SQL Server 2005 Express.

Sto usando il seguente codice. Voglio verificare se esiste un database prima di crearlo. Tuttavia, il numero intero restituito è -1 e questo è il modo in cui MSDN definisce cosa restituirà anche ExecuteNonQuery(). In questo momento, il database esiste ma restituisce ancora -1. Detto questo, come posso fare questo lavoro per ottenere il risultato desiderato?

private static void checkInventoryDatabaseExists(ref SqlConnection tmpConn, ref bool databaseExists) 
{ 
    string sqlCreateDBQuery; 
    try 
    { 
     tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); 

     sqlCreateDBQuery = "SELECT * FROM master.dbo.sysdatabases where name = 
     \'INVENTORY\'"; 

     using (tmpConn) 
     { 
      tmpConn.Open(); 
      tmpConn.ChangeDatabase("master"); 

      using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn)) 
      { 
       int exists = sqlCmd.ExecuteNonQuery(); 

       if (exists <= 0) 
        databaseExists = false; 
       else 
        databaseExists = true; 
      } 
     } 
    } 
    catch (Exception ex) { } 

} 

risposta

43

Come di SQL Server 2005, il vecchio-stile sysobjects e sysdatabases e quelle viste del catalogo sono stati deprecati. Fate questo invece - utilizzare il sys. schema - vista come sys.databases

private static bool CheckDatabaseExists(SqlConnection tmpConn, string databaseName) 
{ 
    string sqlCreateDBQuery; 
    bool result = false; 

    try 
    { 
     tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); 

     sqlCreateDBQuery = string.Format("SELECT database_id FROM sys.databases WHERE Name 
     = '{0}'", databaseName); 

     using (tmpConn) 
     { 
      using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn)) 
      { 
       tmpConn.Open(); 

       object resultObj = sqlCmd.ExecuteScalar(); 

       int databaseID = 0;  

       if (resultObj != null) 
       { 
        int.TryParse(resultObj.ToString(), out databaseID); 
       } 

       tmpConn.Close(); 

       result = (databaseID > 0); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     result = false; 
    } 

    return result; 
} 

Questo funziona con qualsiasi nome di database si passa come un parametro, e restituisce un bool true = database esiste, false = database non esiste (o errore accaduto).

+1

provarlo ora .. executescalar restituisce oggetto quindi devi eseguire il cast prima dell'assegnazione. –

+0

Si genera un'eccezione di "INVENTORY Nome colonna non valido" " –

+1

scusa, sì - il nome del database deve essere racchiuso tra virgolette singole - aggiornato la mia risposta –

6

non dovrebbe questa

"SELECT * FROM master.dbo.sysdatabases where name = \'INVENTORY\'" 

essere questo?

"SELECT * FROM master.dbo.sysdatabases where name = 'INVENTORY'" 

Anche Secondo MSDN

For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.

si sta facendo un SELECT non una dichiarazione DML. Perché non usi invece un metodo ExecuteReader?

+0

alcun effetto sul risultato .. ancora restituisce -1 –

+0

userei ExecuteReader invece dal momento che non sta facendo DML comunque – SQLMenace

+0

questo dovrebbe essere un commento ma buon punto –

2

Non è possibile utilizzare ExecuteNonQuery perché restituirà sempre -1 per SELECT, come mostra il collegamento MSDN.

Dovrete usare processo di un gruppo di risultati ad esempio SELECT DB_ID('INVENTORY') AS DatabaseID o utilizzare una variabile/parametro: SELECT @DatabaseID = DB_ID('INVENTORY')

2

Un'alternativa all'interrogazione delle viste di sistema consiste nell'utilizzare la funzione db_id che restituisce l'ID del database, se esistente, altrimenti null. Esempio T-SQL di seguito:

if (db_id('INVENTORY') is null) 
begin 
    return 0 
end 
else 
begin 
    return 1 
end 
28

La lettura di questo a pochi anni su e c'è un modo più pulito di esprimere questo:

public static bool CheckDatabaseExists(string connectionString, string databaseName) 
{ 
     using (var connection = new SqlConnection(connectionString)) 
     { 
      using (var command = new SqlCommand($"SELECT db_id('{databaseName}')", connection)) 
      { 
       connection.Open(); 
       return (command.ExecuteScalar() != DBNull.Value); 
      } 
     } 
} 
+0

diffidare di SQL injection qui, utilizzare query parametrizzate anziché interpolazione stringa – AndrewK

0

A vantaggio dei ricercatori, se si utilizza Entity Framework, this sarà lavoro:

using (var ctx = new MyDataModel()) 
{ 
    dbExists = System.Data.Entity.Database.Exists(ctx.Database.Connection); 
}