将通用列表C#批量插入SQL Server

如何将c#中的通用列表批量插入SQL Server,而不是循环遍历列表并一次插入一个项目?

我现在有这个;

private void AddSnapshotData() { var password = Cryptography.DecryptString("vhx7Hv7hYD2bF9N4XhN5pkQm8MRfxi+kogALYqwqSuo="); var figDb = "ZEUS"; var connString = String.Format( "Data Source=1xx.x.xx.xxx;Initial Catalog={0};;User ID=appuser;Password={1};MultipleActiveResultSets=True", figDb, password); var myConnection = new SqlConnection(connString); myConnection.Open(); foreach (var holding in _dHoldList) { lbStatus.Text = "Adding information to SQL for client: " + holding.ClientNo; _reports.AddZeusData("tblAllBrooksHoldingsSnapshot", "CliNo, SEDOL, ISIN, QtyHeld, DateOfSnapshot", "'" + holding.ClientNo + "','" + holding.Sedol + "','" + holding.ISIN + "','" + holding.QuantityHeld + "','" + DateTime.Today.ToString("yyyyMMdd") + "'", false, myConnection); } myConnection.Close(); lbStatus.Visible = false; } 

其中dHoldListdHoldList的列表;

 public class DHOLDS : ExcelReport { public String ClientNo { get; set; } public String Sedol { get; set; } public Double QuantityHeld { get; set; } public Double ValueOfStock { get; set; } public String Depot { get; set; } public String ValC4 { get; set; } public String StockR1 { get; set; } public String StockR2 { get; set; } public Double BookCost { get; set; } public String ISIN { get; set; } } 

您可以将列表映射到数据表,然后使用SqlBulkCopy一次插入所有行。

4年后这是我的贡献。 我有同样的问题,我想批量插入但是传递一些不会在数据库中的字段,特别是EF导航属性,所以我写了这个generics类:

 ///  /// This class is intended to perform a bulk insert of a list of elements into a table in a Database. /// This class also allows you to use the same domain classes that you were already using because you /// can include not mapped properties into the field excludedPropertyNames. ///  /// The class that is going to be mapped. public class BulkInsert where T : class { #region Fields private readonly LoggingService _logger = new LoggingService(typeof(BulkInsert)); private string _connectionString; private string _tableName; private IEnumerable _excludedPropertyNames; private int _batchSize; private IEnumerable _data; private DataTable _dataTable; #endregion #region Constructor ///  /// Initializes a new instance of the  class. ///  /// The connection string. /// Name of the table. /// The data. /// The excluded property names. /// Size of the batch. public BulkInsert( string connectionString, string tableName, IEnumerable data, IEnumerable excludedPropertyNames, int batchSize = 1000) { if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException(nameof(connectionString)); if (string.IsNullOrEmpty(tableName)) throw new ArgumentNullException(nameof(tableName)); if (data == null) throw new ArgumentNullException(nameof(data)); if (batchSize <= 0) throw new ArgumentOutOfRangeException(nameof(batchSize)); _connectionString = connectionString; _tableName = tableName; _batchSize = batchSize; _data = data; _excludedPropertyNames = excludedPropertyNames == null ? new List() : excludedPropertyNames; _dataTable = CreateCustomDataTable(); } #endregion #region Public Methods ///  /// Inserts the data with a bulk copy inside a transaction. ///  public void Insert() { using (var connection = new SqlConnection(_connectionString)) { connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default | SqlBulkCopyOptions.KeepIdentity, transaction)) { bulkCopy.BatchSize = _batchSize; bulkCopy.DestinationTableName = _tableName; // Let's fix tons of mapping issues by // Setting the column mapping in SqlBulkCopy instance: foreach (DataColumn dataColumn in _dataTable.Columns) { bulkCopy.ColumnMappings.Add(dataColumn.ColumnName, dataColumn.ColumnName); } try { bulkCopy.WriteToServer(_dataTable); } catch (Exception ex) { _logger.LogError(ex.Message); transaction.Rollback(); connection.Close(); } } transaction.Commit(); } } #endregion #region Private Helper Methods ///  /// Creates the custom data table. ///  private DataTable CreateCustomDataTable() { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); var table = new DataTable(); foreach (PropertyDescriptor prop in properties) { // Just include the not excluded columns if (_excludedPropertyNames.All(epn => epn != prop.Name)) { if (prop.PropertyType.Name == "DbGeography") { var type = typeof(SqlGeography); table.Columns.Add(prop.Name, type); } else { 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) { // Just include the values in not excluded properties if (_excludedPropertyNames.All(epn => epn != prop.Name)) { if (prop.PropertyType.Name == "DbGeography") { row[prop.Name] = SqlGeography.Parse(((DbGeography)prop.GetValue(item)).AsText()).MakeValid(); } else { row[prop.Name] = prop.GetValue(item) ?? DBNull.Value; } } } table.Rows.Add(row); } return table; } #endregion } 

它的用法如下:

 //1st.- You would have a colection of entities: var myEntities = new List(); // [...] With thousands or millions of items // 2nd.- You would create the BulkInsert: myEntityTypeBulk = new BulkInsert(_connectionString, "MyEntitiesTableName", myEntities, new[] { "ObjectState", "SkippedEntityProperty1", "SkippedEntityProperty2" }); // 3rd.- You would execute it: myEntityTypeBulk.Insert(); 

获得的性能和这个类的可重用性值得这个消息。 我希望它有所帮助:

胡安

或者,您也可以将列表转换为XML,如本博文中所述: http : //charleskong.com/blog/2009/09/insert-aspnet-objects-to-sql-server/但SqlBulkCopy方法似乎更好。

另一句话:如果你想通过遍历代码中的元素来解决它,那么如果你在一个事务中完成所有插入操作,那么它可能会提高性能。