C#更换foreach
我正在使用Webservice GET请求获取有关客户的一些信息。我想为请求返回的每个客户向DB插入一条记录 我现在有这个代码:C#更换foreach,c#,C#,我正在使用Webservice GET请求获取有关客户的一些信息。我想为请求返回的每个客户向DB插入一条记录 我现在有这个代码: var container = JsonConvert.DeserializeObject<MarkedCampaigns>(json); string insertDB = ""; foreach (var item in container.items) {
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 .
var container=JsonConvert.DeserializeObject(json);
字符串insertDB=“”;
foreach(container.items中的var项)
{
insertDB+=“将值(“+item.CampaignId+”、“+item.VisiteToreExternalId+”、“+item.Url+”)插入表中(活动ID、CookieId、Url)”;
}
//执行字符串。
容器是来自Get请求的响应。它包含一个项目属性,每个项目代表一个客户
我的问题是,这是将记录插入数据库的正确方法吗?或者有没有一种更简单的方法来使用容器和一些我不熟悉的方法?我强烈建议使用预先准备好的语句。一方面,这将消除每次解析查询时不必要的开销,另一方面,它将强制您使用参数化查询,这将防止类型转换问题——我看到这将发生在您的代码中,因为
url
很可能是某种字符类型,并且您没有添加引号——和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();
}
}
如果您只想对db执行一次调用以执行所有插入,那么一个选项是使用一个存储的进程,该进程包含一个列表: 创建将存储列表的类型的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);
}
}
}
}
活动ID | CookieId | Url
1 | 1 |巴
2 | 2 | foo
要在不使用存储过程的情况下执行此操作,请在注释中查看@Magnus中的此链接
这是Sql注入这一重大问题的一部分,您正面临着一个决定。如果要插入的元素很少,那么可能可以使用一个简单的循环,如@derpisher的回答中所述,但该回答需要为查询的每个元素调用数据库引擎,并且需要自己定义所有参数 最好使用带有多个插入的单个命令文本,因为您只需对数据库引擎进行一次调用,并且如果要插入多个记录,则差异是显而易见的。但如果要使用参数化查询,则最后一种方法很困难,因为要插入的每个值都需要一个参数 相反,我建议您尝试使用 使用这个简单的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命令,直接传递要插入的项目列表和commandtext。您只需要让参数的名称与列表中属性的名称相匹配。必须:不要那样串sql,使用参数化查询。你要求sql注入,@Sayse试图传达的是,你在使用有关sql注入的不安全做法。查找“防止SQL注入”或类似内容:)不仅是不安全的做法,而且是导致错误声明字符串值的做法。您的代码将转换为
值(12,31,https://www.google.com)
请注意URL中缺少的”
,可能的重复项加上准备好的语句/参数化查询通常具有更好的性能。@bradbury9这就是我所说的“删除一些不必要的开销…”如果列表包含很多条目,最好使用table参数。另一种选择是使用SqlBulkCopy。另外,您不需要为此创建存储过程。@Magnus如果没有存储过程,您将如何执行它?您能否像传递任何参数一样传递表格参数以插入blah select from tableparam?(我不是sql高手)看,这正是我发布这个问题时想要的。谢谢。一个问题——“GetSqlConnection返回连接的实例”——它如何知道我的连接?它会使用我EF核心连接吗?或者如何将连接字符串传递给它?抱歉,如果这是一个愚蠢的问题。EF核心,我现在看到了,这是意料之外的。您可以查看这个关于获取EF核心连接的答案,以及另一篇关于在NET Core中集成Dapper的有趣文章GetSqlConnection不是Dapper的一部分。这只是我在这里添加的一个简化来解释这个概念。您可以在类中编写该方法,或者使用建议的方法提取您的连接实例。再次感谢:)
using(IDbConnection cnn = GetSqlConnection())
{
string cmdText = @"INSERT INTO TABLE (CampaignId,CookieId,Url)
VALUES(@CampaignId, @VisitorExternalId, @Url)";
cnn.Execute(cmdText, container.items);
}