come usare sql Bulkcopy per inserire righe di datagridview nella tabella

c# datagridview sql sqlbulkcopy

Domanda

Voglio inserire le righe di datagridview in tabelle del server SQL ... e ora ho usato questo codice per inserire valori di righe da DataGridView nella tabella:

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);
                }
            }
        }

Ma hai un problema nell'inserire i dati: riga vuota (abilita l'aggiunta di righe) da datatgridview essere archiviata nell'ultima riga delle tabelle! si prega di prestare attenzione alle immagini:

inserisci la descrizione dell'immagine qui inserisci la descrizione dell'immagine qui

Risposta accettata

Innanzitutto, alcune osservazioni generali che possono aiutarti a capire meglio la scrittura del codice in C #:

// 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);

Quanto sopra dovrebbe essere scritto per dichiarare la variabile e quindi assegnare il valore:

DataTable dt = GetDataTableFromDGV(DBV);

Quanto segue, da GetDataTableFromDGV , aggiungerà una colonna al DataTable solo se la colonna è visibile:

foreach (DataGridViewColumn column in dgv.Columns)
{
    if (column.Visible)
    {
        dt.Columns.Add();
    }
} 

Il risultato del DataTable di cui sopra viene quindi utilizzato in InsertDTtoDB che chiaramente si aspetta un numero prestabilito di colonne in una posizione ordinale predefinita:

copy.ColumnMappings.Add(0, 1);
// etc...

Quanto sopra sta creando una relazione molto fragile tra il DataTable creato in GetDataTableFromDGV che richiede che la Colonna sia visibile e quindi consumata in InsertDTtoDB .

Anziché utilizzare una relazione ordinale fragile tra DataTable e SqlBulkCopy.ColumnMappings, utilizzare il nome del campo per creare il DataTable e quindi eseguire il mapping a SqlBulkCopy. Il foreach in `GetDataTableFromDGV ', quindi diventa:

// 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();
    }
}

E le ColumnMappings in InsertDTtoDB diventano quindi:

copy.ColumnMappings.Add("Invoice_Id", "DestinationCol1");
copy.ColumnMappings.Add("Software_Id", "DestinationCol2");
// etc...

Quando si aggiungono le righe al DataTable in GetDataTableFromDGV , la variabile cellValues viene dichiarata all'esterno del ciclo foreach, ma i valori vengono continuamente sovrascritti nel ciclo for interno. Anziché aggiungere una serie di oggetti al DataTable, utilizzare i nomi effettivi delle colonne per creare un DataRow e aggiungere il nuovo DataRow al DataTable.

Prendendo in considerazione quanto sopra, il metodo GetDataTableFromDGV diventa quindi:

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;
}

E il metodo InsertDTtoDB diventa quindi:

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);
        }
    }
}

Per rispondere alla tua domanda sul motivo per cui le righe nulle vengono aggiunte al database, sospetto che sia perché ci sono valori null in DataGridView. Supponendo che sia il caso, quindi escludere i valori nulli da DataGridView dall'aggiunta al DataTable. Cancellerei una delle colonne chiave come "Invoice_Id"; il metodo GetDataTableFromDGV diventa quindi:

private DataTable GetDataTableFromDGV(DataGridView dgv)
{
    // assumes the columns in the DataGridView are named as follows:
    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)
    {
        // check if the row has a null "Invoice_Id" and exclude
        if(row.Cells["Invoice_Id"] == null
        {
            continue;
        }

        DataRow newRow = dt.NewRow();
        foreach (string columnName in columns)
        {
            newRow[columnName] = row.Cells[columnName].Value
        }

        dt.Rows.Add(newRow);
    }
    return dt;
}


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow