3 回答

TA貢獻(xiàn)1848條經(jīng)驗(yàn) 獲得超2個(gè)贊
Sql 注入這個(gè)大問題的一部分,你正面臨著一個(gè)決定。如果您要插入的元素很少,那么您可能可以使用@derpisher 的答案中所述的簡(jiǎn)單循環(huán),但該答案需要為查詢的每個(gè)元素調(diào)用數(shù)據(jù)庫引擎,并且您需要自己定義所有參數(shù)。
具有多個(gè)插入的單個(gè)命令文本更可取,因?yàn)槟鷮?duì)數(shù)據(jù)庫引擎進(jìn)行了一次調(diào)用,并且在要插入許多記錄的情況下,差異是顯而易見的。但是,如果您想使用參數(shù)化查詢,則最后一種方法很困難,因?yàn)槟鷮⑿枰獮橐迦氲拿總€(gè)單個(gè)值提供一個(gè)參數(shù)。
相反,我建議您嘗試使用Dapper。
使用這個(gè)簡(jiǎn)單的 ORM 庫,你可以編寫這個(gè)
using(IDbConnection cnn = GetSqlConnection())
{
string cmdText = @"INSERT INTO TABLE (CampaignId,CookieId,Url)
VALUES(@CampaignId, @VisitorExternalId, @Url)";
cnn.Execute(cmdText, container.items);
}
這里的 GetSqlConnection 是一種返回已打開的連接實(shí)例的方法。cmdText 是要執(zhí)行的命令,就好像您只有一個(gè)要插入的記錄一樣。訣竅是 Dapper 添加的 Execute 擴(kuò)展命令,您可以在其中直接傳遞要插入的項(xiàng)目列表和命令文本。您只需要讓參數(shù)名稱與列表中的屬性名稱相匹配。

TA貢獻(xiàn)1865條經(jīng)驗(yàn) 獲得超7個(gè)贊
我強(qiáng)烈建議使用準(zhǔn)備好的語句。這將一方面消除每次解析查詢的一些不必要的開銷,另一方面它會(huì)迫使您使用參數(shù)化查詢,這將防止類型轉(zhuǎn)換問題——我認(rèn)為這會(huì)發(fā)生在您的代碼中,因?yàn)閡rl大多數(shù)可能是某種字符類型,而您沒有添加引號(hào)——以及 SQL 注入。
string query = "INSERT INTO table(CampaignId, CookieId, Url) VALUES (@campaignid, @cookieid, @url)";
using (SqlConnection c = new SqlConnection(connectstring)) {
c.Open();
SqlCommand cmd = new SqlCommand(query, c);
cmd.Parameters.Add(new SqlParameter("@campaignid", SqlDbType.Int, 0)); //use appropriate type/size here
cmd.Parameters.Add(new SqlParameter("@cookieid", SqlDbType.Int, 0)); //use appropriate type/size here
cmd.Parameters.Add(new SqlParameter("@url", SqlDbType.NVarChar, 500)); //use appropriate type/size here
cmd.Prepare();
foreach (var item in container.items) {
cmd.Parameters[0].value = item.CampaignId;
cmd.Parameters[1].value = item.VisitorExternalId;
cmd.Parameters[2].value = item.url;
cmd.ExecuteNonQuery();
}
}

TA貢獻(xiàn)2080條經(jīng)驗(yàn) 獲得超4個(gè)贊
如果您只想對(duì)數(shù)據(jù)庫進(jìn)行一次調(diào)用以執(zhí)行所有插入操作,那么一種選擇是使用帶有列表的存儲(chǔ)過程:
用于創(chuàng)建將存儲(chǔ)我們的列表的類型的 sql:
create type [dbo].CampaignList as table (CampaignId int, CookieId int, [Url] varchar(255))
執(zhí)行插入操作的存儲(chǔ)過程
create procedure [dbo].[spSaveCampaigns]
@CampaignList CampaignList readonly
as
insert into tblCampaigns (CampaignId, CookieId, [Url])
select CampaignId, CookieId, [Url] from @CampaignList;
調(diào)用它的 C#:
public async Task InsertCampigns()
{
var campaigns = new List<Campaign> {new Campaign(1, 1, "bar"), new Campaign(2, 2, "foo") };
using (var sqlConnection = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand("exec [dbo].[spSaveCampaigns] @CampaignList", sqlConnection))
{
await sqlConnection.OpenAsync().ConfigureAwait(false);
using (var table = new DataTable())
{
table.Columns.Add("CampaignId", typeof(int));
table.Columns.Add("CookieId", typeof(int));
table.Columns.Add("Url", typeof(string));
foreach (var campaign in campaigns)
table.Rows.Add(campaign.CampaignId, campaign.CookieId, $"{campaign.Url}");
var parameters = new SqlParameter("@CampaignList", SqlDbType.Structured)
{
TypeName = "dbo.CampaignList",
Value = table
};
cmd.Parameters.Add(parameters);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
}
}
您可以將創(chuàng)建數(shù)據(jù)表的代碼從您的類型中提取到幫助程序中以使其更小。
優(yōu)點(diǎn):參數(shù)化正確。我更喜歡調(diào)用存儲(chǔ)過程而不是對(duì)數(shù)據(jù)庫運(yùn)行 sql(但您可能對(duì)此有不同的看法。)
結(jié)果調(diào)用
await InsertCampigns();
廣告系列 ID | CookieId | 網(wǎng)址
1 | 1 | 酒吧
2 | 2 | 富
要在沒有存儲(chǔ)過程的情況下執(zhí)行此操作,請(qǐng)參閱@Magnus 評(píng)論中的此鏈接
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters#passing-a-table-valued-parameter-to-a-parameterized-sql-statement
- 3 回答
- 0 關(guān)注
- 201 瀏覽
添加回答
舉報(bào)