2010-08-19 73 views
13

簡稱。我有兩個簡單的助手:如何使用SqlCommand創建具有參數化數據庫名稱的DATABASE?

private SqlCommand CreateCommand(string text) 
    { 
     SqlCommand cmd = new SqlCommand(); 
     cmd.Connection = connection; 
     cmd.CommandType = CommandType.Text; 
     cmd.CommandText = text; 
     return cmd; 
    } 

    void SetParameter(SqlCommand cmd, string p, string dbName) 
    { 
     cmd.Parameters.Add(p, SqlDbType.NVarChar); 
     cmd.Parameters[p].Value = dbName; 
    } 

此執行OK:

var cmd = CreateCommand("CREATE DATABASE Demo "+ 
      @"ON (FILENAME = N'c:\demo_data.mdf') "+ 
      @"LOG ON (FILENAME = N'c:\demo_data.mdf.LDF') "+ 
      "FOR ATTACH " + 
      "GO"); 
cmd.ExecuteNonQuery(); 

但這並不:

string dataBaseAttachText = "CREATE DATABASE @dbname " + 
           "ON (FILENAME = @filename) " + 
           "LOG ON (FILENAME = @filenamelog) " + 
           "FOR ATTACH GO"; 
var cmd = CreateCommand(dataBaseAttachText); 

SetParameter(cmd, "@dbname", "Demo"); 
SetParameter(cmd, "@filename", @"c:\demo_data.mdf"); 
SetParameter(cmd, "@filenamelog", @"c:\demo_data.mdf.LDF"); 

cmd.ExecuteNonQuery(); 

爲什麼?

回答

13

DML操作不支持DDL操作的參數,沒有DDL操作的執行計劃。你將需要使用動態SQL

DDL =數據定義語言(創建,刪除,修改....)

DML =數據操縱語言(選擇,更新,刪除,插入)

+0

Rich Hildebrand沒有真正回答這個問題,他有更好的答案。 – 2017-10-12 23:00:59

9

您只能在SQL Server支持它們的地方使用參數。不幸的是,SQL Server不支持參數化的CREATE DATABASE語句(儘管我感覺文件名部分可能支持參數)。

你需要構造SQL自己:

string dataBaseAttachText = "CREATE DATABASE [" + dbName + "] " + 
           "ON (FILENAME = @filename) " + 
           "LOG ON (FILENAME = @filenamelog) " + 
           "FOR ATTACH GO"; 
var cmd = CreateCommand(dataBaseAttachText); 

SetParameter(cmd, "@filename", @"c:\demo_data.mdf"); 
SetParameter(cmd, "@filenamelog", @"c:\demo_data.mdf.LDF"); 

cmd.ExecuteNonQuery(); 

注意:這是易患SQL注入攻擊等等caremust服用;如果您不相信數據庫名稱的來源,請不要這樣做!

如果不能對參數進行參數化,則需要對文件名部分做類似的更改。

+0

謝謝您的回覆! – 2010-08-19 16:44:01

7

可悲你可以通過在DML操作中包裝你的DDL操作來實現這一點。

var createDatabaseQuery = "exec ('CREATE DATABASE ' + @databaseName)"; 

var sqlCommand = new SqlCommand(createDatabaseQuery, sqlConnection); 
sqlCommand.Parameters.Add("@databaseName", SqlDbType.Text); 
sqlCommand.Parameters["@databaseName"].Value = "HelloWorld"; 

sqlCommand.ExecuteNonQuery(); 
+0

雖然它看起來像這種方法提供了防止SQL注入(使用參數),它不會! – 2017-12-17 12:45:23

3

作爲Daniel和Rich的答案的組合之一。通過運行一個DML查詢sp_executesql你可以有一個動態生成的查詢,也可以通過使用QUOTENAME應該逃避在SQL注入人的任何嘗試可能通過英寸

string dataBaseAttachText = @" 
DECLARE @SQLString nvarchar(500); 
DECLARE @ParmDefinition nvarchar(500); 
SET @SQLString = 
    N'CREATE DATABASE ' + QUOTENAME(@dbName) + N' 
     ON (FILENAME = @filename) 
     LOG ON (FILENAME = @filenamelog) 
     FOR ATTACH GO' 
SET ParmDefinition = N'@filename nvarchar(MAX), @filenamelog nvarchar(MAX)' 
EXECUTE sp_executesql @SQLString, @ParmDefinition, @filename = @filename, @filenamelog = @filenamelog"; 

var cmd = CreateCommand(dataBaseAttachText); 

SetParameter(cmd, "@dbname", "Demo"); 
SetParameter(cmd, "@filename", @"c:\demo_data.mdf"); 
SetParameter(cmd, "@filenamelog", @"c:\demo_data.ldf"); 

cmd.ExecuteNonQuery(); 

這應該用適當的執行以下DML的SQL查詢傳遞參數。

CREATE DATABASE [Demo] 
     ON (FILENAME = @filename) 
     LOG ON (FILENAME = @filenamelog) 
     FOR ATTACH GO 
+0

什麼程序集是CreateCommand的一部分?它是否可用.net 45 – user1591131 2016-06-23 13:34:26

+0

@ user1591131 CreateComand是寫在問題頁面頂部的函數。 – 2016-06-23 13:47:02

0

我通過創建適當包裝所有實體的擴展方法解決了這個問題。

/// <summary> 
    /// Quotes the provided string in a sql friendly way using the standard [ and ] characters 
    /// </summary> 
    /// <param name="ObjectName">string to quote</param> 
    /// <example> 
    /// "mytable".QuoteSqlName() would return [mytable] 
    /// "my[complex]table".QuoteSqlName() would return [my[[complex]]table] 
    /// </example> 
    /// <returns>quoted string wrapped by quoting characters</returns> 
    /// <remarks>For dynamic sql this may need to be called multiple times, one for each level of encapsulation.</remarks> 
    public static string QuoteSqlName(this string ObjectName) 
    { 
     return ObjectName.QuoteSqlName(']'); 
    } 

    /// <summary> 
    /// Quotes the provided string in a sql friendly way using the provided character 
    /// </summary> 
    /// <param name="ObjectName">string to quote</param> 
    /// <param name="QuoteCharacter">Character to quote with, use [ or ] for standard sql quoting</param> 
    /// <example> 
    /// "mytable".QuoteSqlName() would return [mytable] 
    /// "my[complex]table".QuoteSqlName() would return [my[[complex]]table] 
    /// "justin's computer".QuoteSqlName('\'') would return 'justin''s computer' 
    /// </example> 
    /// <returns>quoted string wrapped by quoting characters</returns> 
    public static string QuoteSqlName(this string ObjectName, char QuoteCharacter) 
    { 
     return ObjectName.QuoteSqlName(QuoteCharacter, false); 
    } 

    /// <summary> 
    /// Quotes the provided string in a sql friendly way using the provided character 
    /// </summary> 
    /// <param name="ObjectName">string to quote</param> 
    /// <param name="QuoteCharacter">Character to quote with, use [ or ] for standard sql quoting</param> 
    /// <param name="IsNvarChar">if true and QuoteCharacter is ' will prefix the quote with N e.g. N'mytable' vs 'mytable'</param> 
    /// <example> 
    /// "mytable".QuoteSqlName() would return [mytable] 
    /// "my[complex]table".QuoteSqlName() would return [my[[complex]]table] 
    /// "justin's computer".QuoteSqlName('\'') would return 'justin''s computer' 
    /// "mytable".QuoteSqlName('\'',false) would reutrn 'mytable' 
    /// "mytable".QuoteSqlName('[',true) would return [mytable] 
    /// "mytable".QuoteSqlName('\'',true) would reutrn N'mytable' 
    /// </example> 
    /// <returns>quoted string wrapped by quoting characters</returns> 
    public static string QuoteSqlName(this string ObjectName, char QuoteCharacter, bool IsNvarChar) 
    { 
     if (string.IsNullOrEmpty(ObjectName)) 
      return ObjectName; 

     char OtherQuoteCharacter = (char)0; 
     bool UseOtherChar = false; 
     if (QuoteCharacter == ']' || QuoteCharacter == '[') 
     { 
      QuoteCharacter = '['; 
      OtherQuoteCharacter = ']'; 
      UseOtherChar = true; 
     } 

     var sb = new StringBuilder((int)(ObjectName.Length * 1.5) + 2); 
     if (QuoteCharacter == '\'' && IsNvarChar) 
      sb.Append('N'); 

     sb.Append(QuoteCharacter); // start with initial quote character 
     for (var i = 0; i < ObjectName.Length; i++) 
     { 
      sb.Append(ObjectName[i]); 
      // if its a quote character, add it again e.g. ] becomes ]] 
      if (ObjectName[i] == QuoteCharacter || UseOtherChar && ObjectName[i] == OtherQuoteCharacter) 
       sb.Append(ObjectName[i]); 
     } 
     sb.Append(UseOtherChar ? OtherQuoteCharacter : QuoteCharacter); // finish with other final quote character 

     return sb.ToString(); 
    } 

用法:

var QuotedDBName = this.DBName.QuoteSqlName(); 
CreateDBQuery.AppendFormat("USE {0};", QuotedDBName); 
CreateDBQuery.AppendFormat("IF TYPE_ID({0}) IS NULL", DBType.Name.QuoteSqlName('\'', true)); 
CreateDBQuery.AppendFormat(" CREATE TYPE {0} as {1};", DBType.Name.QuoteSqlName(), DBType.Value); 
相關問題