在C#中批量更新

为了在数据库中插入大量的数据,我使用收集所有的插入信息到一个列表中,并把这个列表转换成一个DataTable 。 然后通过SqlBulkCopy将该列表插入到数据库中。

我在哪里发送我生成的列表
LiMyList
其中包含我想要插入数据库的所有批量数据的信息
并将其传递给我的批量插入操作

 InsertData(LiMyList, "MyTable"); 

InsertData在哪里

  public static void InsertData<T>(List<T> list,string TableName) { DataTable dt = new DataTable("MyTable"); clsBulkOperation blk = new clsBulkOperation(); dt = ConvertToDataTable(list); ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal); using (SqlBulkCopy bulkcopy = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["SchoolSoulDataEntitiesForReport"].ConnectionString)) { bulkcopy.BulkCopyTimeout = 660; bulkcopy.DestinationTableName = TableName; bulkcopy.WriteToServer(dt); } } public static DataTable ConvertToDataTable<T>(IList<T> data) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); DataTable table = new DataTable(); foreach (PropertyDescriptor prop in properties) table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); foreach (T item in data) { DataRow row = table.NewRow(); foreach (PropertyDescriptor prop in properties) row[prop.Name] = prop.GetValue(item) ?? DBNull.Value; table.Rows.Add(row); } return table; } 

现在我想要做一个更新操作,有什么办法插入数据是由SqlBulkCopy更新数据到DataBase从C#.Net

我之前所做的是从数据执行批量插入到临时表中,然后使用命令或存储过程来更新有关临时表与目标表的数据。 临时表是一个额外的步骤,但是与行更新数据相比,如果行数很大,则可以通过批量插入和大量更新获得性能提升。

例:

 public static void UpdateData<T>(List<T> list,string TableName) { DataTable dt = new DataTable("MyTable"); dt = ConvertToDataTable(list); using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SchoolSoulDataEntitiesForReport"].ConnectionString)) { using (SqlCommand command = new SqlCommand("", conn)) { try { conn.Open(); //Creating temp table on database command.CommandText = "CREATE TABLE #TmpTable(...)"; command.ExecuteNonQuery(); //Bulk insert into temp table using (SqlBulkCopy bulkcopy = new SqlBulkCopy(conn)) { bulkcopy.BulkCopyTimeout = 660; bulkcopy.DestinationTableName = "#TmpTable"; bulkcopy.WriteToServer(dt); bulkcopy.Close(); } // Updating destination table, and dropping temp table command.CommandTimeout = 300; command.CommandText = "UPDATE T SET ... FROM " + TableName + " T INNER JOIN #TmpTable Temp ON ...; DROP TABLE #TmpTable;"; command.ExecuteNonQuery(); } catch (Exception ex) { // Handle exception properly } finally { conn.Close(); } } } } 

请注意,单个连接用于执行整个操作,以便能够在每个步骤中使用临时表,因为临时表的范围是每个连接。

根据我个人的经验,处理这种情况的最好方法是利用带Table-Valued ParameterUser-Defined Table Type的存储过程。 只需在数据表的列中设置types,并在SQL命令中将所述数据表作为参数传入。

在存储过程中,您可以直接join某个唯一键(如果您正在更新的所有行都存在),或者 – 如果您可能遇到需要同时执行更新和插入的情况 – 请使用SQL Merge命令存储的过程来处理更新和插入(如适用)。

微软既提供了语法参考 ,也提供了一篇关于合并的例子 。

对于.NET片断,只需将参数types设置为SqlDbType.Structured并将所述参数的值设置为包含要更新的logging的数据表即可。

这种方法提供了清晰和便于维护的好处。 虽然可能有一些方法可以提供性能改进(例如将其放到临时表中,然后遍历该表),但是我认为它们被.NET和SQL处理传输表和更新logging本身的简单性所压倒。 吻

不知道我得到了你要存档的点…如果你的问题是快速replace整个表的内容,比我会去truncatehttp://technet.microsoft.com/en-us/library/ms177570&#x3002; aspx )和批量插入新的数据部分。 但是这种方法只会在你没有外键约束的情况下工作。

如果你想真正的更新,请从下面的GuillermoGutiérrez寻找答案。

我会在临时表中插入新值,然后对目标表进行合并,如下所示:

 MERGE [DestTable] AS D USING #SourceTable S ON D.ID = S.ID WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT (...) VALUES (...); 

试试Nuget上提供的SqlBulkTools。

免责声明:我是这个图书馆的作者。

 var bulk = new BulkOperations(); var records = GetRecordsToUpdate(); using (TransactionScope trans = new TransactionScope()) { using (SqlConnection conn = new SqlConnection(ConfigurationManager .ConnectionStrings["SqlBulkToolsTest"].ConnectionString)) { bulk.Setup<MyTable>() .ForCollection(records) .WithTable("MyTable") .AddColumn(x => x.SomeColumn1) .AddColumn(x => x.SomeColumn2) .BulkUpdate() .MatchTargetOn(x => x.Identifier) .Commit(conn); } trans.Complete(); } 

只有“SomeColumn1”和“SomeColumn2”将被更新。 更多的例子可以在这里find

您可以尝试构build一个包含所有数据的查询。 使用case 。 它可能看起来像这样

 update your_table set some_column = case when id = 1 then 'value of 1' when id = 5 then 'value of 5' when id = 7 then 'value of 7' when id = 9 then 'value of 9' end where id in (1,5,7,9) 

我会去一个临时表的方法,因为这样你不locking任何东西。 但是,如果你的逻辑需要只在前端,你需要使用批量复制,我会尝试一个删除/插入的方法,但在同一个SqlTransaction,以确保其完整性是这样的:

 // ... dt = ConvertToDataTable(list); using (SqlConnection cnx = new SqlConnection(myConnectionString)) { using (SqlTranscation tran = cnx.BeginTransaction()) { DeleteData(cnx, tran, list); using (SqlBulkCopy bulkcopy = new SqlBulkCopy(cnx, SqlBulkCopyOptions.Default, tran)) { bulkcopy.BulkCopyTimeout = 660; bulkcopy.DestinationTableName = TabelName; bulkcopy.WriteToServer(dt); } tran.Commit(); } }