![](/img/trans.png)
[英]Bulk Insert DataSet with multiple related tables into SQL Server C#
[英]Bulk insert from C# list into SQL Server into multiple tables with foreign key constraints
我对这个问题一无所知,我们将不胜感激:
我有两个表,一个是主数据表( Table A
),另一个表( Table B
)与Table A
一个条目具有多个条目(具体为18)具有外键关系。
我正在列表中获取数据,并希望将其插入SQL Server数据库中。
我目前正在使用以下模式,但要花费14分钟的时间在Table A
插入100行,并在Table B
插入相应的18 * 100行。
using (SqlConnection conn = new SqlConnection(conStr))
{
foreach (var ticket in Tickets)
{
sql = string.Format(@"INSERT INTO dbo.Tickets([ColumnA], [ColumnB] ,..." + @")
VALUES(@ColumnA, @ColumnB,@ColumnC, @ColumnD, .... +
@"SELECT SCOPE_IDENTITY();");
using (cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@ColumnA", (object)ticket.Id ?? DBNull.Value);
cmd.Parameters.AddWithValue("@ColumnB", (object)ticket.Address ?? DBNull.Value);
cmd.Parameters.AddWithValue("@ColumnC", (object)ticket.Status?? DBNull.Value);
....
conn.Open();
TableA_TicketId = Convert.ToInt32(cmd.ExecuteScalar());
}
}
}
我使用SCOPE_IDENTITY()
从表A中获取每个插入的记录的最新标识,并将其用于插入第二个表中
sql = string.Format(@"INSERT INTO Tickets_Fields ([TableA_TicketId], [FieldName], [Key],[Value])
VALUES (@TableA_TicketId, @FieldName, @Key, @Value);");
using (cmd = new SqlCommand(sql, conn))
{
foreach (var customField in ticket.CustomFields)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@TableA_TicketId", (object)TicketId ?? DBNull.Value);
cmd.Parameters.AddWithValue("@FieldName", (object)"CustomField" ?? DBNull.Value);
...
cmd.ExecuteNonQuery();
}
}
conn.Close();
请提出我是否可以通过任何方式提高此代码的性能。 还是他们有更好/更快的方法?
一些想法:
在整个批次插入过程中,保持同一连接打开。 首先将其打开,然后在完成后将其关闭。
不要在每次循环迭代期间重新创建SqlCommand
。 首先创建一次,然后仅更新参数的值: cmd.Parameters["@x"].Value = …;
。
您正在通过插入单个记录的foreach
循环插入第二个表(B)。 您可以考虑将其替换为单个INSERT INTO TableB (x, y, z) SELECT x, y, z FROM @tvp
,其中@tvp
是一个表值参数 。 从本质上讲,这意味着您可以用要插入到第二个表中的行来填充例如DataTable
,然后将该DataTable
表作为@tvp
。 从SQL Server 2008开始,IIRC支持TVP。 设置其中一个需要第一次学习。
(我不确定上面的INSERT
语句是否会真正起作用,或者TVP是否仅作为存储过程的参数起作用( 例如,参见此示例 )。)
比#3更进一步,将插入到表A和B中的内容移动到DB存储过程中。 此SP将具有进入表A的值作为参数,以及具有进入表B的记录的表值参数。
SqlBulkCopy
是您的朋友
using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlBulkInsertExample
{
class Program
{
static void Main(string[] args)
{
DataTable prodSalesData = new DataTable("ProductSalesData");
// Create Column 1: SaleDate
DataColumn dateColumn = new DataColumn();
dateColumn.DataType = Type.GetType("System.DateTime");
dateColumn.ColumnName = "SaleDate";
// Create Column 2: ProductName
DataColumn productNameColumn = new DataColumn();
productNameColumn.ColumnName = "ProductName";
// Create Column 3: TotalSales
DataColumn totalSalesColumn = new DataColumn();
totalSalesColumn.DataType = Type.GetType("System.Int32");
totalSalesColumn.ColumnName = "TotalSales";
// Add the columns to the ProductSalesData DataTable
prodSalesData.Columns.Add(dateColumn);
prodSalesData.Columns.Add(productNameColumn);
prodSalesData.Columns.Add(totalSalesColumn);
// Let's populate the datatable with our stats.
// You can add as many rows as you want here!
// Create a new row
DataRow dailyProductSalesRow = prodSalesData.NewRow();
dailyProductSalesRow["SaleDate"] = DateTime.Now.Date;
dailyProductSalesRow["ProductName"] = "Nike";
dailyProductSalesRow["TotalSales"] = 10;
// Add the row to the ProductSalesData DataTable
prodSalesData.Rows.Add(dailyProductSalesRow);
// Copy the DataTable to SQL Server using SqlBulkCopy
using (SqlConnection dbConnection = new SqlConnection("Data Source=ProductHost;Initial Catalog=dbProduct;Integrated Security=SSPI;Connection Timeout=60;Min Pool Size=2;Max Pool Size=20;"))
{
dbConnection.Open();
using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
{
s.DestinationTableName = prodSalesData.TableName;
foreach (var column in prodSalesData.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
s.WriteToServer(prodSalesData);
}
}
}
}
}
请注意,默认情况下它将锁定表直到完成,这意味着在该站点上工作的其他任何人都将无法写入同一表。
为了解决这个问题,您可以设置SqlBulkCopy.BatchSize
,但是随后您必须注意,如果导入失败,则有责任删除已经提交的行。
您应该使用SqlTransaction或TransactionScope来确保在两个表中的插入均成功。
从表A中获取Max(id)。使用类似于以下内容的方法在表A中插入记录:
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SomeConnectionString"].ConnectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = 100;
bulkCopy.DestinationTableName = "dbo.Person";
try
{
bulkCopy.WriteToServer(listPerson.AsDataTable());
}
catch (Exception)
{
transaction.Rollback();
connection.Close();
}
}
transaction.Commit();
}
然后将记录插入表B。您将知道需要从哪个ID计算ID,因为在插入之前已选择Max(id)。
请参阅本文以获取具有最少代码行的BulkInsert的完整示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.