简而言之。我有两个简单的帮手:
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();
为什么?
答案 0 :(得分:16)
DML操作支持参数而不支持DDL操作,DDL操作没有执行计划。您将需要使用动态SQL
DDL =数据定义语言(创建,删除,更改....)
DML =数据操作语言(选择,更新,删除,插入)
答案 1 :(得分: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注入攻击是可以接受的,所以必须小心谨慎;如果您不信任数据库名称的来源,请不要这样做!
如果文件名部分无法参数化,则需要对文件名部分进行类似的更改。
答案 2 :(得分: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();
答案 3 :(得分:3)
作为丹尼尔和里奇的答案的一部分。通过向sp_executesql
运行DML查询,您可以拥有一个动态构建的查询,同样通过使用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
答案 4 :(得分: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);
答案 5 :(得分:0)
我通过调用存储的存储过程“ sp_executesql”中的构建来解决此任务。 用于创建数据库的连接字符串指向“ master”。 完整的SQL语句是参数值的一部分:
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
using (SqlCommand command = new SqlCommand("sp_executesql", connection))
{
command.CommandType = CommandType.StoredProcedure;
var sql = $"CREATE DATABASE NewDatabaseName";
command.Parameters.Add("MyParameterName", SqlDbType.NVarChar).Value = sql;
connection.Open();
command.ExecuteNonQuery();
}
}