Ist das ein Fehler in Datatable-API? Die Änderungen werden gespeichert / ausgeführt in der „falschen Reihenfolge“

StackOverflow https://stackoverflow.com/questions/1027095

  •  06-07-2019
  •  | 
  •  

Frage

Edit:. Keine Kommentare, ob Sie denken, das ein .NET-Bug ist oder würde nicht geschätzt

Ich habe einen Fehler, ich habe es geschafft, auf das folgende Szenario zu vereinfachen:

Ich habe eine Datentabelle, wo die Primärschlüssel konsekutiven gehalten werden müssen, z.B. wenn Sie eine Zeile zwischen anderen Zeilen einfügen, müssen Sie zuerst die ID der nachfolgenden Zeilen erhöhen, um Platz zu machen, und dann die Zeile eingefügt werden.

Und wenn Sie eine Zeile löschen, müssen Sie die ID aller nachfolgenden Zeilen verringern die Lücke durch die Zeile in der Tabelle zu füllen.

Testfall, der richtig

funktioniert

Beginnen Sie mit drei Zeilen in der Tabelle, mit IDs 1, 2 und 3.

Dann löscht ID = 2 und ID = 2 gesetzt, wo ID = 3 (um die Lücke zu füllen); das funktioniert richtig. Die dataTable.GetChanges () enthält die gelöschte Zeile, und dann die modifizierte Zeile; wenn Sie DataAdapter.Update (Tabelle) führen Sie es führt in Ordnung.

Testfall, der nicht funktioniert

Wenn Sie jedoch mit zwei Reihen (IDs 1 und 2) starten, dann setzt ID = 3, wo ID = 2, und legen Sie ID = 2, dann begehen (oder akzeptiert) ändern. Dies sollte nun der gleiche Zustand wie der erste Test.

Dann machen Sie die gleichen Schritte wie zuvor, das heißt löschen ID = 2 und eingestellt ID = 2, wo ID = 3, aber jetzt sind die dataTable.GetChanges () in der falschen Reihenfolge sind. Die erste Zeile ist eine modifizierte Reihe und die zweite Reihe ist die gelöschte Zeile. Dann, wenn Sie DataAdapter.Update (Tabelle) versuchen wird, einen Primärschlüssel Verletzung geben -. Versuchte, eine Zeile zu einer bereits bestehenden Zeile zu ändern, bevor es gelöscht

Umgehung

Ich kann das Problem einer Abhilfe denken, das heißt es so zwingen, die Zeilen zuerst begangen werden gelöscht, und dann Zeilen geändert, und dann Zeilen hinzugefügt. Aber warum ist das passiert? Gibt es eine andere Lösung?

Ich glaube, ich habe ein ähnliches „Problem“ gesehen, bevor sie mit Wörterbüchern, dass, wenn Sie einige Elemente hinzufügen, löschen dann wieder einlegen, dann werden sie nicht in der gleichen Reihenfolge, die Sie hinzugefügt, um sie (wenn Sie das aufzählen Wörterbuch).

Hier sind zwei NUnit Tests, die das Problem zeigen:

[Test]
public void GetChanges_Working()
{
    // Setup ID table with three rows, ID=1, ID=2, ID=3
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);
    idTable.Rows.Add(3);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

Ausgabe:

Deleted: 2
Modified: 3 = 2

1 passed, 0 failed, 0 skipped, took 4.27 seconds (NUnit 2.4).

Nächster Test:

[Test]
public void GetChanges_NotWorking()
{
    // Setup ID table with two rows, ID=1, ID=2
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Move old ID=2 to ID=3, and add ID=2
    idTable.Select("ID = 2")[0]["ID"] = 3;
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

Ausgabe:

Modified: 3 = 2
Deleted: 2
TestCase 'GetChanges_NotWorking'
failed: 
  1st row in GetChanges should be deleted row
  Expected: Deleted
  But was:  Modified
War es hilfreich?

Lösung

Es ist kein Bug, der Punkt ist, dass Sie IDs in einer (sehr) nicht dem Standard entsprechende Art und Weise verwenden. Zwei Antworten:

1) Verwendung DataTable.GetChanges (DataRowState.Modified) Ihre Updates zu verarbeiten, um (ich denke, es wäre gelöscht, geändert, eingefügt) werden. Dies ist, was Sie haben auch mit Master / Detail-Beziehungen zu tun (vor .net 3.0)

2) Rethink Ihr Design, die im Allgemeinen ID unveränderlich sein sollte und ermöglichen Lücken usw. Ihr alle Datenbankoperationen machen viel zuverlässiger und viel einfacher. Sie können eine andere Spalte verwenden, um eine fortlaufende Nummerierung zu halten, um den Benutzer zu präsentieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top