Arbeiten mit Data Tables

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Arbeiten mit Data Tables

    Hi,

    Ich habe eine Data Table, nennen wir sie BaseTable, die einige tausend Zeilen an Daten enthält.

    Zu einem Zeitpunkt wird immer nur ein Block von einigen Dutzend Zeilen benötigt. Deshalb erstelle ich einen Extrakt in eine Arbeitstabelle, nennen wir sie SelectTable.

    VB.NET-Quellcode

    1. Dim strExpression As String = "..."
    2. Dim SelectTable() As DataRow = BaseTable.Select(strExpression)


    Die Zeilen der SelectTable möchte ich fallweise verändern oder auch löschen.

    Update:

    VB.NET-Quellcode

    1. 'Update SelectTable and BaseTable
    2. SelectTable(SelectIndex).Item("tabCntTrue") = cnt + 1 'Updates BaseTable too


    Wie der Kommentar schon sagt, wird durch den Update der SelectTable auch die BaseTable verändert. Soweit ist alles in Ordnung !

    Delete:

    VB.NET-Quellcode

    1. SelectTable(SelectIndex).Delete() 'Does not work


    Wie der Kommentar schon sagt, gibt es hier ein Problem. Die Zeile wird zwar in der SelectTable gelöscht ... aber wenn ich dann die BaseTable über den Index Range 0 bis BaseTable.Rows.Count - 1 lese, erhalte ich einen Fehler, weil eine gelöschte Zeile addressiert wird.

    Ich habe das jetzt so gelöst, dass ich die zu löschende Zeile über den primary key in der BaseTable lokalisiere und dann die BaseTable lösche:

    VB.NET-Quellcode

    1. BaseTable.Rows.RemoveAt(BaseIndex) 'Deletes SelectTable too


    Das funktioniert so zwar, aber ich frage mich, ob das wirklich so gemacht werden muss. Kann man eine Löschung in der SelectTable nicht in die BaseTable "reflektieren"?

    Ich hoffe, ich habe mein Anliegen verständlich ausgedrückt.

    LG
    Peter

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Peter329“ ()

    @Peter329 Ich würde das anders rum machen:
    Lösche die Zeile in der Basistabelle und update die Selecttabelle.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Ich würde das anders rum machen:
    Lösche die Zeile in der Basistabelle und update die Selecttabelle.


    ehem ... genauso mache ich das doch.

    Es sieht also so aus, dass nichts anderes übrig bleibt, als so zu arbeiten. So richtig verstehe ich das Wesen einer mit "Select" erstellten Tabelle noch nicht ...

    LG
    Peter

    Peter329 schrieb:


    ehem ... genauso mache ich das doch.


    Deiner Beschreibung nach machst Du das nicht.
    Du beschreibst:
    - lösche Datensatz in SelectTabel
    - lösche Datensatz in BaseTable

    Rod schreibt:
    - lösche Datensatz in BaseTabel
    - SelectTable.Clear()
    - SelectTabe neu füllen

    bzw. die letzten beiden Punkte zu einem Update zusammenfassen.
    Den mit "does not work" markierten Code führe ich natürlich nicht aus!

    Um die babylonische Sprachverwirrung aufzuheben, hier mein aktueller (funktionierender) Code:

    VB.NET-Quellcode

    1. SelectIndex = ... 'Determine, which row is to be processed
    2. 'entweder:
    3. 'Update
    4. SelectTable(SelectIndex).Item("tabCntTrue") = cnt + 1 'Updates BaseTable too
    5. 'oder:
    6. 'Delete
    7. BaseIndex = ... 'Determine BaseIndex via PK
    8. BaseTable.Rows.RemoveAt(BaseIndex) 'Deletes SelectTable too


    Im Update Fall ändere ich die SelectTable, im Delete Fall lösche ich in der BaseTable.

    Jetzt klar was ich treibe?

    Und die Frage ist, warum man hier unterschiedlich agieren muss ... es wäre doch schöner, wenn ich auch im Delete Fall mit der SelectTable arbeiten könnte,

    Wie schon gesagt, ich verstehe das Wesen der SelectTable nicht so richtig.

    LG
    Peter

    Peter329 schrieb:

    Ich habe das jetzt so gelöst, dass ich die zu löschende Zeile über den primary key in der BaseTable lokalisiere und dann die BaseTable lösche:

    VB.NET-Quellcode

    1. BaseTable.Rows.RemoveAt(BaseIndex) 'Deletes SelectTable too
    Das funktioniert so zwar, aber ich frage mich, ob das wirklich so gemacht werden muss.

    Jo - prinzipiell muss das so gemacht werden.
    Du musst dir klarmachen, dass eine der Hauptfunktionen einer Datatable ist, alle Änderungen - also auch die Löschungen - sich zu merken, damit sie später an eine Db gesandt werden können.
    Daher lässt die DataRow.Delete()-Methode die Row nicht verschwinden, sondern markiert sie als Deleted, damit später diese Löschung auch übermittelt werden kann.
    Du hast damit genau den Unterschied herausgefunden zw. DataRow.Delete() und DataTable.RemoveAt(index).
    Wie gesagt: Delete merkt sich eine Information für den späteren Abgleich, RemoveAt() verhält sich wie mans von normalen Auflistungen auch kennt.

    Peter329 schrieb:

    Kann man eine Löschung in der SelectTable nicht in die BaseTable "reflektieren"?
    Ja, geht auch.
    Normalerweise macht das der TableAdapter intern, nachdem die Db geupdated wurde, aber man kann das auch erzwingen, mit
    DataTable.AcceptChanges()

    Peter329 schrieb:


    Wie schon gesagt, ich verstehe das Wesen der SelectTable nicht so richtig.


    Wenn nicht Du, wer dann?

    Die SelectTable ist eine eigenständige Tabelle, die sich definiert aus einer begrenzten (selektierten) Anzahl der Basis-Tabelle. Steht ja da und ist auch so.
    Löscht Du in der einen Tabelle etwas, dann kann die andere Tabelle da nichts von wissen.

    Die Frage ist, ob es für Deine Applikation an der Stelle nicht besser wäre mit einer Bindingssource zu arbeiten. Auf die Bindigsource läßt sich ein Filter legen und du hast deine Selektion.
    Brauchst Du z.B. ein DGV mit der vollständigen Tabelle machst du 2 Bindissource, eine ohne Filter, eine weitere mit Filter. Löscht Du einen Datensatz dann ist der auch gelöscht, was sich über die Bindingssourcen direkt auf das jeweilige DGV auswirkt.
    Ich kenne aber Deine Anwendung nicht, deshalb ist das hier geschilderte auch wirklich nur als Beispiel zu sehen.

    Dksksm schrieb:

    Peter329 schrieb:

    Wie schon gesagt, ich verstehe das Wesen der SelectTable nicht so richtig.

    Die SelectTable ist eine eigenständige Tabelle,...
    Ist sie nicht.
    Die Verwirrung ist ein typisches Ergebnis schlechter Benamung -
    Nomen est Omen!


    Es ist nämlich keine Tabelle, sondern es ist ein DataRow-Array - steht da ja auch.

    VB.NET-Quellcode

    1. Dim SelectTable() As DataRow = BaseTable.Select(strExpression)

    richtig benamt wäre

    VB.NET-Quellcode

    1. Dim selectedRows() As DataRow = BaseTable.Select(strExpression)
    und es wäre garnet möglich, SelectTable nicht zu verstehen, denn das gäbe es garnet.

    ErfinderDesRades schrieb:


    Du musst dir klarmachen, dass eine der Hauptfunktionen einer Datatable ist, alle Änderungen - also auch die Löschungen - sich zu merken, damit sie später an eine Db gesandt werden können.
    Daher lässt die DataRow.Delete()-Methode die Row nicht verschwinden, sondern markiert sie als Deleted, damit später diese Löschung auch übermittelt werden kann.


    Ok, das hat mich jetzt doch entscheidend weiter gebracht.

    SelectTable ist also keine Tabelle im eigentlichen Sinn, sondern eher eine VIEW (analog zur View im DB2). Die View ist "updateable", d.h. Änderungen schlagen auf die BaseTable durch. Jedoch ein Delete entfernt die Zeile zwar aus der View, aber in der BaseTable wird die Zeile nur als gelöscht markiert. Wenn man auf diesen Index zugreift, kriegt man die erwähnte Exception.

    Ich hoffe, ich habe alles richtig verstanden.

    LG
    Peter

    Peter329 schrieb:

    Die View ist "updateable", d.h. Änderungen schlagen auf die BaseTable durch.
    Wieder anders herum:
    Eine geänderte Basistabelle führt zum Update des Views.
    Primat hat immer die Basistabelle.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Peter329 schrieb:

    SelectTable ist also keine Tabelle im eigentlichen Sinn, sondern eher eine VIEW
    Nein, nix "eher" und so ähnlich, sondern es ist ein DataRow-Array.
    Genauso ein DataRow(), wie wenn du machen würdest:

    VB.NET-Quellcode

    1. dim someRows(3) As DataRow
    2. someRows(0)=basisTable.Rows(0)
    3. someRows(1)=basisTable.Rows(4)
    4. someRows(2)=basisTable.Rows(5)
    5. someRows(3)=basisTable.Rows(70)
    Ein Array halt.

    Peter329 schrieb:

    Änderungen schlagen auf die BaseTable durch.
    Änderungen ändern die Objekte. Wenn dasselbe Objekt im DataRow-Array ist, und ausserdem inne basisTable, und du änderst es, dann kannst du natürlich aus beiden Auflistungen (sowohl dem array als auch der basisTable) dieses Objekt abrufen, und wirst es geändert vorfinden - was sonst?
    "Durchschlagen" würde ich das nicht nennen.

    ok ... "SelectedTable" ist also ein eigenständiges Object. Das hab ich jetzt verstanden. Und weil "SelectedTable" einfach ein Array von DataRows ist, sollte ich das Dingens vielleicht besser "SelectedRows" nennen. Richtig? Aber um nicht wieder in die babylonische Sprachverwirrung zu verfallen, belassen wir es mal für dieses Posting bei "SelectedTable".

    Zitat RFG:

    Eine geänderte Basistabelle führt zum Update des Views.
    Primat hat immer die Basistabelle.

    Zitat EDR

    Änderungen ändern die Objekte. Wenn dasselbe Objekt im DataRow-Array ist, und ausserdem inne basisTable, und du änderst es, dann kannst du natürlich aus beiden Auflistungen (sowohl dem array als auch der basisTable) dieses Objekt abrufen, und wirst es geändert vorfinden - was sonst?

    Das verstehe ich jetzt nicht. Durch meine Definition ...

    VB.NET-Quellcode

    1. Dim SelectTable() As DataRow = BaseTable.Select(strExpression)


    ... sind doch einige Zeilen aus BaseTable in den Array SelectTable eingestellt worden.

    Da müsste es doch jetzt nach dem Posting von EDR egal sein, ob ich eine dieser Zeilen in der BaseTable ändere oder in der SelectTable. Es ist doch immer das gleiche Objekt.

    Das widerspricht aber dem Posting von RFG, wonach die BaseTable das "Primat" hat.

    ?

    LG
    Peter

    ErfinderDesRades schrieb:

    Primat
    kam ja von mir.
    Immer am Original arbeiten, die Anzeigedaten sind halt GUI, und die haben wir ja von unseren Daten sorgfältig getrennt:
    Primärdaten - die Source,
    Sekundärdatren - die Anzeige.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Na, wie dem auch sei.

    Peter329 schrieb:

    ... sind doch einige Zeilen aus BaseTable in den Array SelectTable eingestellt worden.
    Da müsste es doch jetzt nach dem Posting von EDR egal sein, ob ich eine dieser Zeilen in der BaseTable ändere oder in der SelectTable. Es ist doch immer das gleiche Objekt.
    Dazu täte ich sagen: Stimmt genau - ist vollkommen schnuppe.
    Ob und wie das mit der Primaten-Theorie zusammenhängt oder widerspricht ist mir nicht ganz klar, ist mir eiglich auch egal.
    ich arbeite eh nie mit untypisierten Datarows, von daher weiß ich auch garnet genau, was Peter329 da eiglich treibt.
    Bei mir gibts immer 3 Ebenen:
    1. Das Dataset mit allen Tabellen und den folglich verschieden typisierten Datarows.
    2. Daran angebunden diverse BindingSources, die filtern, sortieren, selectieren
    3. Daran wiederum angeschlossen das Gui
    Und je nachdem, was zu tun ist, greife ich auf die Daten zu:
    Massenoperationen führe ich im Dataset durch.
    Für Operationen mit einzelnen selektierten DataRows muss ich natürlich aus den BindingSources die selektierte Row rausholen.
    Und in seltenen Fällen puhle ich Daten auch mal direkt aus dem Control aus, etwa bei OwnerDrawing kann das vorkommen.

    Ist schon so ähnlich wie ich glaub, was Rod meint, also wenns möglich ist, bevorzuge ich immer die "oberflächen-fernere" Datenverarbeitung.

    Aber hat mit dem zitierten Gedanken garnix zu tun, denn sowohl BaseTable als auch SelectTable sind oberflächen-fern - von daher piepe (bzw muss man die Umstände angugge).

    ErfinderDesRades schrieb:


    Bei mir gibts immer 3 Ebenen:
    1. Das Dataset mit allen Tabellen und den folglich verschieden typisierten Datarows.
    2. Daran angebunden diverse BindingSources, die filtern, sortieren, selectieren
    3. Daran wiederum angeschlossen das Gui
    [list=1]
    [/list]
    Was ja genau meinem Vorschlag (siehe Post 7) entspricht.