为了账号安全,请及时绑定邮箱和手机立即绑定

C# 替换 foreach

C# 替换 foreach

C#
胡子哥哥 2021-11-21 15:35:16
我正在使用 Webservice GET 请求来获取有关客户的一些信息。我想为每个从请求返回的客户向数据库插入一条记录。我现在有这个代码:            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 .Container 是来自 Get 请求的响应。它包含一个 Item 属性,其中每个项目代表一个客户。我的问题是,这是将记录插入到我的数据库的正确方法吗?或者有没有更简单的方法使用容器和一些我不熟悉的方法?
查看完整描述

3 回答

?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

Sql 注入这个大问题的一部分,你正面临着一个决定。如果您要插入的元素很少,那么您可能可以使用@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 扩展命令,您可以在其中直接传递要插入的项目列表和命令文本。您只需要让参数名称与列表中的属性名称相匹配。


查看完整回答
反对 回复 2021-11-21
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

我强烈建议使用准备好的语句。这将一方面消除每次解析查询的一些不必要的开销,另一方面它会迫使您使用参数化查询,这将防止类型转换问题——我认为这会发生在您的代码中,因为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();

    }

}


查看完整回答
反对 回复 2021-11-21
?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

如果您只想对数据库进行一次调用以执行所有插入操作,那么一种选择是使用带有列表的存储过程:


用于创建将存储我们的列表的类型的 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);

                    }

                }

            }

        }

您可以将创建数据表的代码从您的类型中提取到帮助程序中以使其更小。


优点:参数化正确。我更喜欢调用存储过程而不是对数据库运行 sql(但您可能对此有不同的看法。)


结果调用


await InsertCampigns();

广告系列 ID | CookieId | 网址


1 | 1 | 酒吧


2 | 2 | 富


要在没有存储过程的情况下执行此操作,请参阅@Magnus 评论中的此链接


https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters#passing-a-table-valued-parameter-to-a-parameterized-sql-statement


查看完整回答
反对 回复 2021-11-21
  • 3 回答
  • 0 关注
  • 175 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信