Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#更换foreach_C# - Fatal编程技术网

C#更换foreach

C#更换foreach,c#,C#,我正在使用Webservice GET请求获取有关客户的一些信息。我想为请求返回的每个客户向DB插入一条记录 我现在有这个代码: var container = JsonConvert.DeserializeObject<MarkedCampaigns>(json); string insertDB = ""; foreach (var item in container.items) {

我正在使用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 .
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);
}