多插入更新解决方案的最佳解决方案
Posted
技术标签:
【中文标题】多插入更新解决方案的最佳解决方案【英文标题】:best solution for multiple insert update solution 【发布时间】:2019-02-05 10:16:15 【问题描述】:作为初学者,努力理解 C# 和 Npgsql。以下代码示例:
// Insert some data
using (var cmd = new NpgsqlCommand())
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p)";
cmd.Parameters.AddWithValue("p", "Hello world");
cmd.ExecuteNonQuery();
到目前为止,这样的多个插入和更新语句的语法很清楚:
cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p);INSERT INTO data1...;INSERT into data2... and so on";
但是对于应该在其中处理一个语句的循环来说,正确的解决方案是什么。
这行不通:
// Insert some data
using (var cmd = new NpgsqlCommand())
foreach(s in SomeStringCollectionOrWhatever)
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO data (some_field) VALUES (@p)";
cmd.Parameters.AddWithValue("p", s);
cmd.ExecuteNonQuery();
似乎这些值将被“连接”或被记住。我看不到任何“清除”现有 cmd 对象的可能性。
我的第二个解决方案是将整个“使用”块包装到循环中。但是每个循环都会创建一个新对象。这对我来说似乎很难看。
那么,我的问题的最佳解决方案是什么?
【问题讨论】:
【参考方案1】:要有效地插入大量行,请查看 Npgsql 的 bulk copy feature - 该 API 更适合(并且更有效)插入大量行,而不是像您尝试做的那样将 INSERT 语句连接成批处理。
【讨论】:
不,我不想以这种方式将数据从外部复制到数据库,反之亦然。这只是一个关于循环内后续 sql 的问题。 (例如改变参数值)【参考方案2】:如果您想通过更改参数值重新运行相同的 SQL,您可以执行以下操作:
using (var cmd = new NpgsqlCommand("INSERT INTO data (some_field) VALUES (@p)", conn))
var p = new NpgsqlParameter("p", DbType.String); // Adjust DbType according to type
cmd.Parameters.Add(p);
cmd.Prepare(); // This is optional but will optimize the statement for repeated use
foreach(var s in SomeStringCollectionOrWhatever)
p.Value = s;
cmd.ExecuteNonQuery();
【讨论】:
好的,我明白了。 NpgsqlCommand.CreateParameter 方法呢? API Doc 说,将创建一个新的参数实例。那么,这种方法的工作方式与您上面建议的方式相同吗? 这个想法是在执行相同命令时重用 NpgsqlParameter 的相同实例。如何创建该实例并不重要 -NpgsqlCommand.CreateParameter()
或 new NpgsqlParameter()
都可以。【参考方案3】:
如果您需要大量行并且性能是关键,那么我会推荐 Npgsql 的批量复制功能,正如 @Shay 提到的那样。但是,如果您正在寻找无需批量复制的快速方法,我建议您使用Dapper。
考虑下面的例子。
假设您有一个名为 Event 的类和一个要添加的事件列表。
List<Event> eventsToInsert = new List<Event>
new Event() EventId = 1, EventName = "Bday1" ,
new Event() EventId = 2, EventName = "Bday2" ,
new Event() EventId = 3, EventName = "Bday3"
;
将列表添加到如下所示数据库的 sn-p。
var sqlInsert = "Insert into events( eventid, eventname ) values (@EventId, @EventName)";
using (IDbConnection conn = new NpgsqlConnection(cs))
conn.Open();
// Execute is an extension method supplied by Dapper
// This code will add all the entries in the eventsToInsert List and match up the values based on property name. Only caveat is that the property names of the POCO should match the placeholder names in the SQL Statement.
conn.Execute(sqlInsert, eventsToInsert);
// If we want to retrieve the data back into the list
List<Event> eventsAdded;
// This Dapper extension will return an Ienumerable, so i cast it to a List.
eventsAdded = conn.Query<Event>("Select * from events").ToList();
foreach( var row in eventsAdded)
Console.WriteLine($"row.EventId row.EventName was added");
-HTH
【讨论】:
以上是关于多插入更新解决方案的最佳解决方案的主要内容,如果未能解决你的问题,请参考以下文章