我正在使用Webservice GET请求来获取有关客户的一些信息。我想为从请求返回的每个客户向DB插入一条记录。
我现在有以下代码:
var container = JsonConvert.DeserializeObject<MarkedCampaigns>(json);
string insertDB = "";
foreach (var item in container.items)
{
insertDB += "INSERT INTO TABLE (CampaignId,CookieId,Url) values(" + item.CampaignId + "," + item.VisitorExternalId + "," + item.Url + ");";
}
//EXECUTE STRING .
容器是Get请求的响应。它包含一个Item属性,每个项目代表一个客户。
我的问题是,这是将记录插入数据库的正确方法吗?还是有使用容器的更简单方法以及一些我不熟悉的方法?
答案 0 :(得分:3)
我强烈建议使用准备好的陈述。一方面,这将消除每次解析查询的不必要的开销,另一方面,它将迫使您使用参数化查询,这将避免类型转换的问题-我认为这会在您的代码中发生,因为{{ 1}}很可能是某些字符类型,您没有添加引号和SQL注入。
url
答案 1 :(得分:3)
如果您只想对数据库进行一次调用以进行所有插入操作,那么一种选择是使用带有列表的存储过程:
用于创建将存储我们的列表的类型的sql:
create type [dbo].CampaignList as table (CampaignId int, CookieId int, [Url] varchar(255))
执行插入操作的存储过程
create procedure [dbo].[spSaveCampaigns]
@CampaignList CampaignList readonly
as
insert into tblCampaigns (CampaignId, CookieId, [Url])
select CampaignId, CookieId, [Url] from @CampaignList;
调用它的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);
}
}
}
}
您可以将用于创建数据表的代码从您的类型中拉出到帮助器中,以缩小该数据表。
优点: 正确设置了参数。 我更喜欢调用存储的proc,而不是针对db运行sql(但您对此可能会有不同的看法。)
结果调用
await InsertCampigns();
CampaignId | CookieId |网址
1 | 1 |酒吧
2 | 2 | foo
要在没有存储过程的情况下执行此操作,请在评论中查看@Magnus的链接
答案 2 :(得分:2)
作为Sql Injection的一个大问题的一部分,您面临着要做出的决定。如果您要插入的元素很少,则可能可以使用一个简单的循环,如@derpisher的答案中所述,但是该答案需要为查询的每个元素调用数据库引擎,并且您需要定义自己的所有参数。
具有多个插入内容的单个命令文本是更可取的,因为您对数据库引擎进行了一次调用,并且在要插入多个记录的情况下,差异很明显。但是,如果要使用参数化查询,则后一种方法比较困难,因为对于每个要插入的值,您都需要一个参数。
相反,我建议您尝试使用Dapper。
使用这个简单的ORM库,您可以编写
using(IDbConnection cnn = GetSqlConnection())
{
string cmdText = @"INSERT INTO TABLE (CampaignId,CookieId,Url)
VALUES(@CampaignId, @VisitorExternalId, @Url)";
cnn.Execute(cmdText, container.items);
}
这里,GetSqlConnection是一种方法,它返回已打开的连接的实例。 cmdText是要执行的命令,就好像您只有一条记录要插入一样。诀窍是Dapper添加的Execute extension命令,您可以在其中直接传递要插入的项目列表和命令文本。您只需要使参数名称与列表内的属性名称匹配即可。