Noc*_*ceo 4 c# t-sql sql-server
有什么方法可以参数化INSERT插入多行的SQL 语句(在C#中)?目前,我只能想到一种方法来生成用于插入多行的语句,但这对于SQL注入是相当开放的:
string sql = " INSERT INTO my_table"
+ " (a, b, c)"
+ " VALUES";
// Add each row of values to the statement
foreach (var item in collection) {
sql = sql
+ String.Format(" ({0}, {1}, {2}),",
aVal, bVal, cVal);
}
// Remove the excessive comma
sql = sql.Remove(sql.Length - 1);
Run Code Online (Sandbox Code Playgroud)
什么是更聪明/更安全的方法?
您可以在循环内添加参数,例如:
using (var comm = new SqlCommand()) {
var counter = 0;
foreach (var item in collection) {
sql = sql + String.Format(" (@a{0}, @b{0}, @c{0})," counter);
comm.Parameters.AddWithValue("@a" + counter, aVal);
comm.Parameters.AddWithValue("@b" + counter, bVal);
comm.Parameters.AddWithValue("@c" + counter, cVal);
counter++;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我真的不会像这样进行多行插入。IIRC查询中的最大参数数量约为2100,并且这可能很快变得非常大。无论如何,当您遍历一个集合时,您可以将其发送到循环中的数据库中,例如:
using (var con = new SqlConnection("connectionString here"))
{
con.Open();
var sql = "INSERT INTO my_table (a, b, c) VALUES (@a,@b,@c);"
using (var comm = new SqlCommand(sql, con))
{
comm.Parameters.Add("@a", SqlDbType.Int);
comm.Parameters.Add("@b", SqlDbType.NVarChar);
comm.Parameters.Add("@c", SqlDbType.Int);
foreach (var item in collection) {
{
comm.Parameters["@a"].Value = aVal;
comm.Parameters["@b"].Value = bVal;
comm.Parameters["@b"].Size = bVal.Length;
comm.Parameters["@c"].Value = cVal;
comm.ExecuteNonQuery();
}
}
}
Run Code Online (Sandbox Code Playgroud)
该语句仅准备一次(并且比具有100个参数的巨大语句要快),并且当一条记录失败时,它不会使所有记录失败(为此添加一些异常处理)。如果您想在一条记录失败时全部失败,则可以将其包装在事务中。
编辑:当然,当您必须定期输入1000行时,这种方法也不是最有效的,您的DBA可能会开始抱怨。还有其他方法可以解决此问题,以消除数据库中的压力:例如,在数据库中创建一个存储过程,该存储过程将插入xml文档中的数据,或者使用表值参数。 NYCdotNet撰写了2个关于这些选项的不错的博客,我不会在这里重新创建它们,但是值得探讨(我将按照指南将一些代码粘贴到博客的下面,但应归因于此:NYCdotNet) XML文档方法 表值参数
关于TVP的博客中的“肉”(在VB.NET中,但这无关紧要):
因此,我创建了这种“通用”表值类型:
CREATE TYPE dbo.UniqueIntegerList AS TABLE
(
TheInteger INT NOT NULL
PRIMARY KEY (TheInteger)
);
Run Code Online (Sandbox Code Playgroud)
创建保存的存储过程
接下来,我创建了一个新的存储过程,该过程将接受我的新表值类型作为参数。
CREATE PROC DoTableValuedParameterInsert(@ProductIDs
dbo.UniqueIntegerList READONLY)
AS BEGIN
INSERT INTO ProductsAccess(ProductID)
SELECT TheInteger AS [ProductID]
FROM @ProductIDs;
END
Run Code Online (Sandbox Code Playgroud)
在此过程中,我传入一个名为@ProductIDs的参数。这是我在上一步中创建的“ dbo.UniqueIntegerList”类型。SQL Server对此进行了检查,并说:“哦,我知道这是什么-该类型实际上是一个表”。因为它知道UniqueIntegerList类型是一个表,所以可以从中选择,就像可以从任何其他表值变量中选择一样。您必须将参数标记为READONLY,因为SQL 2008不支持更新和返回传递的表值参数。
创建保存例程
然后,我必须在我的业务对象上创建一个新的保存例程,该例程将调用新的存储过程。准备Table-Valued参数的方法是创建一个与Table-Valued类型具有相同列签名的DataTable对象,将其填充,然后将其作为SqlDbType.Structured传递到SqlParameter对象中。
Public Sub SaveViaTableValuedParameter()
'Prepare the Table-valued Parameter'
Dim objUniqueIntegerList As New DataTable
Dim objColumn As DataColumn =
objUniqueIntegerList.Columns.Add("TheInteger", _
System.Type.GetType("System.Int32"))
objColumn.Unique = True
'Populate the Table-valued Parameter with the data to save'
For Each Item As Product In Me.Values
objUniqueIntegerList.Rows.Add(Item.ProductID)
Next
'Connect to the DB and save it.'
Using objConn As New SqlConnection(DBConnectionString())
objConn.Open()
Using objCmd As New SqlCommand("dbo.DoTableValuedParameterInsert")
objCmd.CommandType = CommandType.StoredProcedure
objCmd.Connection = objConn
objCmd.Parameters.Add("ProductIDs", SqlDbType.Structured)
objCmd.Parameters(0).Value = objUniqueIntegerList
objCmd.ExecuteNonQuery()
End Using
objConn.Close()
End Using
End Sub
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2865 次 |
| 最近记录: |