如何使用SqlCommand创建带参数化数据库名称的DATABASE?

Mik*_*lov 16 c# sql-server ado.net

简而言之.我有两个简单的助手:

    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;
    }
Run Code Online (Sandbox Code Playgroud)

这执行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();
Run Code Online (Sandbox Code Playgroud)

但这不是:

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();
Run Code Online (Sandbox Code Playgroud)

为什么?

SQL*_*ace 20

DML操作支持参数而不支持DDL操作,DDL操作没有执行计划.您将需要使用动态SQL

DDL =数据定义语言(创建,删除,更改....)

DML =数据操作语言(选择,更新,删除,插入)


Dan*_*haw 10

您只能在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(); 
Run Code Online (Sandbox Code Playgroud)

注意:这对SQL注入攻击是可以接受的,因此必须小心谨慎; 如果您不信任数据库名称的来源,请不要这样做!

如果不能对参数化进行参数化,则需要对文件名部分进行类似的更改.


小智 9

遗憾的是,您可以通过在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();
Run Code Online (Sandbox Code Playgroud)

  • 看起来这种方法提供了防止SQL注入的保护(使用参数可以做到),但事实并非如此! (3认同)

Sco*_*ain 5

作为丹尼尔和里奇答案的结合。通过运行 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(); 
Run Code Online (Sandbox Code Playgroud)

这应该使用传递的正确参数执行以下 DML 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(); 
Run Code Online (Sandbox Code Playgroud)