如何使用sql Bulkcopy在表中插入datagridview行

时间:2015-07-31 10:11:28

标签: c# sql datagridview sqlbulkcopy

我想将datagridview行插入sql server表... 现在使用此代码从表格中的DataGridView插入行值:

private DataTable GetDataTableFromDGV(DataGridView dgv)
        {
            var dt = new DataTable();
            foreach (DataGridViewColumn column in dgv.Columns)
            {
                if (column.Visible)
                {
                    dt.Columns.Add();
                }
            }
            object[] cellValues = new object[dgv.Columns.Count];
            foreach (DataGridViewRow row in dgv.Rows)
            {
                for (int i = 0; i < row.Cells.Count; i++)
                {
                    cellValues[i] = row.Cells[i].Value;
                }
                dt.Rows.Add(cellValues);
            }
            return dt;
        }

        private void InsertDTtoDB(string ConnectionString, string TableName, DataGridView DGV)
        {
            DataTable dt = new DataTable();
            dt = GetDataTableFromDGV(DGV);
            using (SqlConnection cn = new SqlConnection(ConnectionString))
            {
                cn.Open();
                using (SqlBulkCopy copy = new SqlBulkCopy(cn))
                {                        
                    copy.ColumnMappings.Add(0, 1);
                    copy.ColumnMappings.Add(1, 2);
                    copy.ColumnMappings.Add(2, 3);
                    copy.ColumnMappings.Add(3, 4);
                    copy.ColumnMappings.Add(4, 5);
                    copy.DestinationTableName = TableName;
                    copy.WriteToServer(dt);
                }
            }
        }

但是插入数据有问题: 从datatgridview的空行(启用添加行)存储在最后的表行中! 请关注图片帮助:

enter image description here enter image description here

1 个答案:

答案 0 :(得分:1)

首先,一些可能有助于您更好地理解在C#中编写代码的一般性观察:

select email
from person
group by email
having count(*)>1

应编写上述内容以声明变量,然后分配值:

// this line is declaring a new variable named 'dt' 
// and assigning it an instance of a new DataTable
DataTable dt = new DataTable();
// this line is immediately overwriting the new DataTable 
// assigned to 'dt' with the DataTable returned from 'GetDataTableFromDGV'
dt = GetDataTableFromDGV(DGV);

以下内容来自DataTable dt = GetDataTableFromDGV(DBV); ,只有在列可见时才会向DataTable添加列:

GetDataTableFromDGV

然后在foreach (DataGridViewColumn column in dgv.Columns) { if (column.Visible) { dt.Columns.Add(); } } 中使用上面的DataTable的结果,显然期望在预定义的序数位置有一定数量的列:

InsertDTtoDB

以上是在copy.ColumnMappings.Add(0, 1); // etc... 中创建的DataTable之间创建了一个非常脆弱的关系,它要求Column可见,然后在GetDataTableFromDGV中使用。

不是在DataTable和SqlBulkCopy.ColumnMappings之间使用脆弱的序数关系,而是使用该字段的名称来创建DataTable,然后映射到SqlBulkCopy。然后,`GetDataTableFromDGV&#39;中的foreach变为:

InsertDTtoDB

然后// assumes the columns in the DataGridView are named as follows: var columns = new[] {"Id", "Invoice_Id", "Software_Id", "Price", "Quantity", "Sum" } var dt = new DataTable(); foreach (DataGridViewColumn column in dgv.Columns) { // note: this is case-sensitive if (columns.Contains(column.Name)) { dt.Columns.Add(); } } 中的ColumnMappings变为:

InsertDTtoDB

copy.ColumnMappings.Add("Invoice_Id", "DestinationCol1"); copy.ColumnMappings.Add("Software_Id", "DestinationCol2"); // etc... 中将行添加到DataTable时,GetDataTableFromDGV变量在foreach循环之外声明,但值在内部for循环中不断被覆盖。不是将对象数组添加到DataTable,而是使用实际的列名来构建DataRow并将新的DataRow添加到DataTable。

考虑到上述因素,cellValues方法变为:

GetDataTableFromDGV

然后private DataTable GetDataTableFromDGV(DataGridView dgv) { // use your actual columns names instead of Col1, Col2, etc... var columns = new[] {"Invoice_Id", "Software_Id", "Price", "Quantity", "Sum" } var dt = new DataTable(); foreach (DataGridViewColumn column in dgv.Columns) { if (columns.Contains(column.Name)) { dt.Columns.Add(); } } foreach (DataGridViewRow row in dgv.Rows) { DataRow newRow = dt.NewRow(); foreach (string columnName in columns) { newRow[columnName] = row.Cells[columnName].Value } dt.Rows.Add(newRow); } return dt; } 方法变为:

InsertDTtoDB

要回答关于为什么将空行添加到数据库的问题,我怀疑是因为DataGridView中有空值。假设是这种情况,那么将DataGridView中的空值排除在添加到DataTable之外。我关键其中一个关键列,例如&#34; Invoice_Id&#34 ;;然后private void InsertDTtoDB(string ConnectionString, string TableName, DataGridView DGV) { DataTable dt = GetDataTableFromDGV(DGV); using (SqlConnection cn = new SqlConnection(ConnectionString)) { cn.Open(); using (SqlBulkCopy copy = new SqlBulkCopy(cn)) { // update the "DestinationCol[x]" values to the destination column names copy.ColumnMappings.Add("Invoice_Id", "DestinationCol1"); copy.ColumnMappings.Add("Software_Id", "DestinationCol2"); copy.ColumnMappings.Add("Price", "DestinationCol3"); copy.ColumnMappings.Add("Quantity", "DestinationCol4"); copy.ColumnMappings.Add("Sum", "DestinationCol5"); copy.DestinationTableName = TableName; copy.WriteToServer(dt); } } } 方法变为:

GetDataTableFromDGV