2015-09-10 6 views
5

Ich versuche zu bearbeiten DataTable Gefüllt von NpgsqlDataAdapter. Nach dem Aufruf Fill() Methode habe ich nur eine Zeile in DataTable. Dann änderte ich nur den Wert einer Spalte und versuchte wie folgt zu aktualisieren.DBConcurrency Exception beim Aktualisieren mit Dataadapter

enter image description here

Dann bin ich diesen Fehler:

DBConcurrencyException occured

Mein Code ist:

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: Ich habe drei Felder als Primärschlüssel und ich rufe nur zwei Felder in Select-Anweisung. Ist es ein Grund für DBConcurrency Fehler? Aber ich bin in der Lage, die Tabelle mit dem gleichen (drei Feldern als Primärschlüssel) Parametern in SQL Server zu aktualisieren 2005.

UPDATE:

ich die Lösung gefunden und die Lösung ist I erstellt und verwenden zweiten Dataadapter um Daten zu aktualisieren. benutzte ich getAllData (NpgSqlDataAdapter) Tabelle zu füllen, wie

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

Und auch neben Adapter zu aktualisieren, da

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) 
    { 
     ...... 
    } 

Ich habe versucht, eine Menge und fand erstellt, dass NpgsqlDataAdapter hatte Problem mit Spalte -Code . Als ich es weggelassen habe, hat es funktioniert. DataType des Spaltencodes ist Varchar. Ich weiß nicht, warum das passiert ist. Hat jemand eine Idee?

+0

können Sie bitte das genaue Schema für Tabelle stocktable (Sie können dies tun, indem Sie '\ d stocktable' in psql ausführen)? Was ist der Typ der variablen Menge? Beachten Sie, dass es nur einen Primärschlüssel in einer PG-Tabelle geben kann, nicht drei (obwohl Sie beliebig viele Indizes haben können). –

+0

Noch eine Sache, die helfen würde, ist das Ergebnis der Abfrage, die Sie vornehmen (dh die genauen Werte)) –

Antwort

4

Dies ist, weil DataAdapter standardmäßig Optimistic Concurrency verwendet. Wenn Sie also versuchen, eine Zeile zu aktualisieren, die nicht mehr in der Datenbank vorhanden ist oder geändert wurde, schlägt die Aktualisierung von DataAdapter mit der obigen Ausnahme fehl.

Mögliche Szenarien:

  • Zwischen Ihnen die Daten in das Client auswählen und auf die Update senden, ein anderer Benutzer zu löschen oder diese Zeile aus seiner Anwendung zu aktualisieren.
  • Es kann sein, dass Sie die Daten von woanders in Ihrer Anwendung löschen.

Zum Beispiel:

  1. Sie die DataTable füllen, die für das Update verwendet wird.
  2. Löscht die Zeile mit Code = 1101 (zum Beispiel) direkt aus der Datenbank, d. H. Sie verwenden DataTable hier nicht. Dies emuliert einen anderen Benutzer, der die Zeile mit Code = 1101 aus einer anderen Anwendung löscht. Oder ein anderer Teil in Ihrem Code löscht die Zeile mit Code = 1101.
  3. Wählt die Zeile mit Code = 1101 aus der DataTable, dies ist nur um zu zeigen, dass es immer noch da ist, obwohl Sie es aus der Datenbank selbst gelöscht haben.
  4. Bearbeitet die Spalte in der Zeile mit Code = 1101 in der DataTable. Dies muss geschehen, andernfalls ignoriert der Aufruf von Update diese Zeile beim Aktualisieren.
  5. Führt das Update aus. Dadurch wird die Ausnahme ausgelöst, da Sie versuchen, eine Zeile (die nicht mehr existiert) in der Datenbank zu aktualisieren.

Wenn Sie Last Writer Wins implementieren möchten, fügen Sie den folgenden Code ein:

cb.ConflictOption = ConflictOption.OverwriteChanges; 

es auch noch eine weitere mögliche Sache: Wenn Sie Decimal/numeric als Spalten in der DB haben sie diesen Fehler verursachen sogar obwohl die Daten gleich aussehen. Dies liegt an einem Dezimalrundungsfehler.

Eine wichtige Anmerkung: Sie sollten immer parameterized queries übrigens verwenden. Diese Art von String-Verkettungen sind für SQL Injection offen.

Verwandte Themen