2015-09-10 11 views
5

Sto tentando di modificare DataTable compilato da NpgsqlDataAdapter. Dopo aver chiamato il metodo Fill(), ho solo una riga in DataTable. Poi ho cambiato il valore di una sola colonna e ho provato ad aggiornare come di seguito.Errore DBConcurrency durante l'aggiornamento tramite Dataadapter

enter image description here

Poi sto ottenendo questo errore:

DBConcurrencyException occured

Il mio codice è:

NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT sn, 
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "' 
ORDER BY EDate ASC", DatabaseConnectionpg); 
DataTable ds1 = new DataTable(); 
ds1.Clear(); 
getAllData.Fill(ds1); 

if (ds1.Rows.Count > 0) 
{ 
    ds1.Rows[0]["Quantity"] = qty;// calculated value 
} 
ds1 = ds1.GetChanges(); 

NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(getAllData); 
//getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); }; 
//cb.SetAllValues = false; 
getAllData.DeleteCommand = cb.GetDeleteCommand(); 
getAllData.InsertCommand = cb.GetInsertCommand(); 
getAllData.UpdateCommand = cb.GetUpdateCommand(); 
int x = getAllData.Update(ds1); 
if (x > 0) 
{ 
    ds1.AcceptChanges(); 
} 

EDIT: Ho tre campi come chiavi primarie e sto solo chiamando due campi nell'istruzione select. È la causa dell'errore DBConcurrency? Ma io sono in grado di aggiornare la tabella con le stesse (tre campi come chiave primaria) i parametri in SQL Server 2005.

UPDATE:

ho trovato la soluzione e la soluzione è che ho creato e usato secondo DataAdapter per aggiornare i dati. Ho usato getAllData (NpgSqlDataAdapter) per riempire tabella come

NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT 
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "' 
ORDER BY EDate ASC", DatabaseConnectionpg); 

e ha anche creato adattatore prossimo per aggiornare come

NpgsqlDataAdapter updateadap= new NpgsqlDataAdapter("SELECT sn, quantity FROM stocktable WHERE Code='" + product + "' 
ORDER BY EDate ASC", DatabaseConnectionpg); 
NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(updateadap); 
    //getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); }; 
    //cb.SetAllValues = false; 
    updateadap.DeleteCommand = cb.GetDeleteCommand(); 
    updateadap.InsertCommand = cb.GetInsertCommand(); 
    updateadap.UpdateCommand = cb.GetUpdateCommand(); 
    int x = updateadap.Update(ds1); 
    if (x > 0) 
    { 
     ...... 
    } 

ho provato un sacco e ha scoperto che NpgsqlDataAdapter ha avuto problemi con la colonna Codice . Quando l'ho usato, ha funzionato. DataType del codice della colonna è varchar. Non so perché questo stava accadendo. Qualcuno ha idea al riguardo?

+0

puoi pubblicare lo schema esatto per tabella di magazzino (puoi farlo eseguendo '\ d stocktable' in psql)? Inoltre, qual è il tipo di variabile qty? Nota che può esserci solo una chiave primaria in una tabella PG, non tre (anche se puoi avere tutti gli indici che vuoi) –

+0

Un'altra cosa che sarebbe di aiuto è il risultato della query che stai facendo (cioè i valori esatti) –

risposta

4

Questo perché DataAdapter utilizza Optimistic Concurrency per impostazione predefinita. Ciò significa che se si sta tentando di aggiornare una riga che non esiste più nel database o modificata, l'aggiornamento da DataAdapter avrà esito negativo con l'eccezione sopra.

possibili scenari:

  • Tra voi che selezionate i dati nel client e l'invio dell'aggiornamento , un altro utente è la cancellazione o l'aggiornamento di questo riga dalla sua applicazione.
  • È possibile che si stiano eliminando i dati da qualche altra parte nell'applicazione.

Per esempio:

  1. Si riempie il DataTable che verrà utilizzato per l'aggiornamento.
  2. Elimina la riga con Code = 1101 (ad esempio) direttamente dal database, ad esempio non si utilizza lo DataTable qui. Ciò sta emulando un altro utente che elimina la riga con Code = 1101 da un'altra applicazione. O qualche altra parte nel tuo codice che cancella la riga con Code = 1101.
  3. Seleziona la riga con Code = 1101 da DataTable, questo è solo per mostrare che è ancora lì anche se è stato eliminato dal database stesso.
  4. Modifica la colonna Quantity nella riga con Code = 1101 nello DataTable. Questo deve essere fatto, altrimenti la chiamata ad Update ignorerà questa riga durante l'aggiornamento.
  5. Esegue l'aggiornamento, genererà l'eccezione poiché si sta tentando di aggiornare una riga che (non esiste più) nel database.

Se si desidera implementare Last Writer Wins, aggiungere il seguente codice:

cb.ConflictOption = ConflictOption.OverwriteChanges; 

Inoltre v'è ancora una cosa possibile: se avete Decimal/numeric come colonne nel DB che può causare questo errore anche anche se i dati sembrano uguali. Ciò è dovuto a un errore di arrotondamento decimale.

Una nota importante: È consigliabile utilizzare sempre parameterized queries. Questo tipo di concatenazione di stringhe è aperto per SQL Injection.

Problemi correlati