Se dobbiamo sviluppare applicazioni Windows Form “quick and dirty” su basi di dati non troppo complesse, niente ereditarietà o self-relationship per intenderci, con il DataSet ed i TableAdapter possiamo soddisfare le nostre esigenze con un po’ di drag and drop ed alcuni click del mouse.

Update in-line

Tutto bello se non fosse che per quello che non ci viene dato in automatico dobbiamo sudare le famose 7 camicie. Mi è capitato recentemente di dover applicare ad una DataGridView collegata ad un DataSet la modifica in-line, ovvero il salvataggio dei dati all’uscita dalla cella. Dopo innumerevoli tentativi sono giunto alla seguente conclusione:

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    this.dataGridView1.EndEdit();
    this.customersBindingSource.EndEdit();
    if (this.dataSet1.HasChanges(DataRowState.Modified))
    {
       this.customersTableAdapter.Update(this.dataSet1.Customers);
    }
}

In pratica nell’handler dell’evento CellValueChanged del DataGridView procedo alla chiamata dei metodi EndEdit rispettivamente sulla DataGridView e sul BindingSource collegato in modo da propagare la modifica alla sorgente dati bindata alla griglia. Successivamente controllo se ci sono modifiche (può essere omesso visto lo scopo dell’evento scatenato) ed a quel punto chiamo il metodo Update del TableAdapter che procede alla persistenza dei dati sullo storage.

Performance tip

Lavorando con un insieme maggiore di record il TableAdapter soffre di un po’ di lentezza se gli passiamo nel metodo Update tutta la tabella. Per migliorare le performance possiamo utilizzare direttamente il DataAdapter, accessibile tramite la proprietà Adapter, al quale passiamo un dataset con le modifiche da persistere, ecco come fare:

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    this.dataGridView1.EndEdit();
    this.customersBindingSource.EndEdit();
    if (this.dataSet1.HasChanges(DataRowState.Modified))
    {
        DataSet ds = this.dataSet1.GetChanges(DataRowState.Modified);
        this.customersTableAdapter.Adapter.Update(ds);
    }
}

Quando si lavora con il DataSet devono essere gestite opportunamente concorrenza e caricamento dei dati in modo da evitare perdita di informazioni ed un utilizzo pesante delle risorse. Nel primo caso la gestione viene definita tramite opportuna configurazione del TableAdapter, nel secondo caso è compito nostro implementare dei meccanismi di paginazione dei dati, ma questa è un’altra storia…