2 Datatables kombinierern

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von King2k7.

    2 Datatables kombinierern

    Hallo,
    ich habe 2 DataTables. Diese Versuche ich zu einer DataTable zu kombinieren. Der Aufbau der Datatables ist wie folgt:

    Datatable Client

    Datatable Artikel


    Es geht darum das eine Liste gedruckt werden soll. Dafür benötigte ich zuerst den Namen und danach die Artikel die zu dem Clienten gehören. Leider weiß ich nicht genau wie ich die Listen am besten kombinieren um die benötigte formatierung zu bekommen.
    Gibt es eine möglichkeit die beiden Datatables zu kombinieren das eine neue Liste erstellt wird?
    Kombinieren? Das ergibt m.E. so nicht soviel Sinn. Ich würd das eher mit passender For-Schleife machen.

    VB.NET-Quellcode

    1. Dim Druckdaten As New List(Of String)
    2. For Each SingleClient In Client 'Ein Grund für mich, bei DataTable-Namen im Plural zu arbeiten
    3. Druckdaten.Add("gekaufte Sachen von " & SingleClient.first_name & " " & SingleClient.last_name & ":")
    4. For Each Item In Artikel.Where(Function(x) x.ClientRow Is SingleClient) '*
    5. Druckdaten.Add(Item.Artikel & ", " & Item.Bemerkung)
    6. Next
    7. Next
    8. 'hier mit Druckdaten weitermachen.

    *wenn Du nicht mit DataSets arbeitest, dann: For Each Item In Artikel.Where(Function(x) x.ClientID = SingleClient.id)

    btw: es heißt "Sab Simplex", nicht "Sap Simplex". Und "Kompresse" wird mit einem P geschrieben. Und Verbandschere mit einem S ;)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed:
    Leider geht es bei mir nicht so einfach. Kann natürlich auch sein das der VB Code nicht korrekt in C# übersetzt ist?!

    C#-Quellcode

    1. List<string> Druckdaten = new List<string>();
    2. foreach (var SingleClient in dt_clientlist) // Fehler 1
    3. {
    4. Druckdaten.Add("gekaufte Sachen von " + SingleClient.first_name + " " + SingleClient.last_name + ":");
    5. foreach (var Item in dt_cache.Where(x => x.ClientRow == SingleClient)) // Fehler 2
    6. Druckdaten.Add(Item.Artikel + ", " + Item.Bemerkung);
    7. }



    Es kommen 2 Fehlermeldungen:

    Quellcode

    1. Fehler 1 Eine foreach-Anweisung kann nicht für Variablen vom Typ "DataTable" verwendet werden, da "DataTable" keine öffentliche Instanzendefinition für "GetEnumerator" enthält.


    und

    Quellcode

    1. Fehler 2 "DataTable" enthält keine Definition für "Where", und es wurde keine verfügbare Where-Erweiterungsmethode gefunden, die ein erstes Argument vom Typ "DataTable" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis).



    Zu den Rechtschreibfehlern: Ja das weiß ich, sind einfach nur Flüchtigkeitsfehler gewesen ;)
    Fehler 1: Du kannst da nicht einfach den DataTable-Typ hinschreiben. Du musst die Instanz verwenden, also z.B. DeinDataSet.dt_Client. Genauso Fehler 2.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Komme nicht wirklich zu einer Lösung. Habe mir auf der Microsoft Homepage nochmal ein paar Beispiele angesehn.

    Mir ist leider nicht klar wie genau ich die foreach Schleife befüllen muss.

    C#-Quellcode

    1. sqlKlasse getClientName = new sqlKlasse();
    2. DataTable dt_clientlist = new DataTable();
    3. dt_clientlist = getClientName.selectQuery("SELECT last_name, first_name, b_day, id FROM clients WHERE id =" + dt_cache.Rows[0]["ClientID"].ToString());
    4. DataSet dataSet = new DataSet("Bestellungen");
    5. dataSet.Tables.Add(dt_clientlist); // Liste mit Klienten
    6. dataSet.Tables.Add(dt_cache); // Liste mit den Artikeln
    7. List<string> Druckdaten = new List<string>();
    8. foreach (var SingleClient in dataSet.Tables["dt_clientlist"].Rows) // Ein Grund für mich, bei DataTable-Namen im Plural zu arbeiten
    9. {
    10. Druckdaten.Add("gekaufte Sachen von " + SingleClient.first_name + " " + SingleClient.last_name + ":");
    11. foreach (var Item in Artikel.Where(x => x.ClientRow == SingleClient)) // *
    12. Druckdaten.Add(Item.Artikel + ", " + Item.Bemerkung);
    13. }


    Ich packe mein neues Dataset mit meinen 2 DataTables. Aber dann?

    King2k7 schrieb:

    ich habe 2 DataTables.
    Zwischen denen eine Beziehung besteht.
    Wenn du diese Beziehung denn auch tatsächlich als DataRelation modelliert hast, wird es kinderleicht:

    VB.NET-Quellcode

    1. foreach(var clnt in dt_Clients){
    2. foreach(var article in clnt.GetArticleRows()) Debug.WriteLine($"{clnt.last_name}: {article.Artikel}");
    3. }
    So ungefähr.
    Du kannst nicht erwarten, dass wir hier korrekten Code schreiben, ohne deine Solution in einem VisualStudio geöffnet zu haben.
    Und Wie gesagt: Es hängt daran, dass du die Beziehungen richtig modellierst.
    Siehe dazu auch: Grundlagen: Relationale Datenmodellierung
    Umsetzung davon:
    vier Views-Videos


    C#-Quellcode

    1. foreach (var SingleClient in dataSet.Tables["dt_clientlist"].Rows)
    Das sollte doch schon schiefgehen, da SingleClient dann vom Typ object ist. Ich bin zwar in C# nicht drin, aber Zugriff auf ClientMembers wie first_name gehen doch da ohne Cast gar nicht. Aber werden wir konkret: Was steht in dt_clientlist und Artikel ab Post#5, Zeile#4 ganz genau drin? Keine Umschreibung, sondern bitte Inhalt posten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Was steht in dt_clientlist und Artikel ab Post#5, Zeile#4 ganz genau drin? Keine Umschreibung, sondern bitte Inhalt posten.

    Das sind die Inhalte meiner DataTables:


    Nach dem Post von ErfinderDesRades habe ich gesehn das meine DataTables nicht miteinander verbunden sind. Ich denke das ist auch einer der Fehler die hier vorliegen.
    Nun habe ich anhand der Anleitungen folgendes Dataset mit dem Namen DruckDataset erstellt:


    Ich denke ich muss meinen Code anpassen und mit denn im Designer angelegten DataTables arbeiten anstelle von 2 unabhängigen die keine Verbindung haben. Meine Frage ist jetzt wie fülle ich DataTables bzw. wie greife ich darauf zu?
    Ich sehe diese zwar im Designer aber habe aus dem Code keinen Zugriff drauf?!

    Projekt ErfinderDesRades:

    Mein Projekt:



    Im Beispiel Projekt (aus Grundlagen: Relationale Datenmodellierung ) von ErfinderDesRades kann ich im Code den Namen des DataSet schreiben und erhalte andere Möglichkeiten als bei mir. Eine Einstellung fehlt noch, weiß aber nicht was.
    Wie würde das befüllen der Datatable "Client" und "Artikel" aussehn, weil wie gesagt im Moment sind diese zwar angelegt aber ich kann sie nicht füllen oder darauf zugreifen.



    Vielen Dank für eure Hilfe und vor allem die Geduld.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „King2k7“ ()

    Ok, Du hast ein tDS. Nun brauchst Du auf Deinem Form eine tDS-Instanz. Gibt mehrere Wege. Ganz oben in der ToolBox ist Dein tDS, welches Du als Komponente auf's Form ziehen kannst. Alternativ ziehst Du aus dem Datenquellenfenster eine Table auf's Form, dann landet auf dem Form als Komponente: eine tDS-Instanz, eine BindingSource; auf dem Form selber: ein gebundenes DGV und ein BindingNavigator. Is wurscht, Hauptsache ist, dass Du eine tDS-Instanz hast. Dann kannst Du z.B. schreiben: DeineTdsInstanz.Client.AddClientRow("Max", "Mustermann", Date.Today). Oder eben auch

    VB.NET-Quellcode

    1. Dim ClientSpecificItems = DeineTdsInstanz.Client.First.GetArtikelRows

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Es passt nicht ganz zur ursprünglichen Frage, wollte aber kein neues Thema dafür eröffnen.

    Ich habe eine DataTable gefüllt mit Namen und Artikeln auf form1. Jetzt möchte ich gern auf form2 ein Datagridview befüllen mit den Werten der DataTable. Ich habe etwas gegoogelt wo verschiedene Methoden gezeigt worden sind wie man Werte von Form1 auf Form2 bekommt.
    Allerdings stand auch oft da das dies nicht gemacht wird weil es als "unsauberer" Code angesehn wird.

    Jetzt ist meien Frage: Wie würde man es richtig machen? Also was ist eine "saubere" Methode um Werte aus einer DataTable(form1) in ein Datagridview(form2) zu laden?
    Man übergibt die DataTable-Instanz an Form2? Oder notfalls das ganze tDS.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich habe dafür einiges brimborium geschrieben, um mit einem Befehl sog. "form-übergreifendes Databinding" zu ermöglichen.
    Ansonsten ist sone Übergeberei immer mit einigem Umgestöpsel verbunden - jedenfalls, wenn man im Form-Designer Databindings eingerichtet hat.
    Daten laden, speichern, verarbeiten - einfachste Variante

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Und wie schon einmal erzählt: Umstöpselei ist nicht notwendig, wenn man eine eigene BindingSource (BS) für's tDS auf alle Forms haut und alle anderen DataTable-verbundenen BSs nicht an die Form-eigene tDS-Instanz hängt, sondern an die tDS-BS. Dann braucht man nur bei SubForm-Erstellung die DataSource der tDS-BS neu zu setzen und fertig.

    Beispiel: hier die Form-eigene DataSet-Instanz-Komponente. Dazu die tDS-BindingSource (markiert)

    die an diese tDS-Instanz angebunden ist

    und die DataTable-BS, die nicht an die tDS-Instanz direkt gebunden ist, sondern indirekt über die tDS-BS


    Ruft man dann das SubForm z.B. so auf

    VB.NET-Quellcode

    1. Private Sub ShowSubForm()
    2. Using Dialog As New FrmSubForm
    3. Dialog.BsTds.DataSource = OriginalTds 'oder eben bei SubSubForming BsTds.Current statt OriginalTds; gerne auch zu einem tDS gecastet
    4. Dialog.ShowDialog(Me)
    5. End Using
    6. End Sub

    sind alle Daten im SubForm. Keine Kopien, sondern die originalen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    ICh danke. Das sieht viel versprechend aus. Werde es nachher mal testen :)



    VaporiZed schrieb:

    Beispiel: hier die Form-eigene DataSet-Instanz-Komponente. Dazu die tDS-BindingSource (markiert)


    Ich habe jetzt mal versucht dein Beispiel auf meinen Code zu übertragen. Leider geht es nicht.
    Erstmal meine Einstellungen:







    C-Quellcode

    1. private void btn_auswahl_anzeigen_Click(object sender, EventArgs e)
    2. {
    3. using (frm_anforderung_anzeigen Dialog = new frm_anforderung_anzeigen())
    4. {
    5. Dialog.bindingSource1.DataSource = OriginalTds; // Hier wird mit das bindingSource1 als Fehler angezeigt
    6. Dialog.ShowDialog(this);
    7. }
    8. }


    Als ich versucht habe deinen Code 1 zu 1 nachzustellen wird mir folgender FEhler angezeigt:


    Fehler CS1061 "frm_anforderung_anzeigen" enthält keine Definition für "bindingSource1", und es wurde keine verfügbare bindingSource1-Erweiterungsmethode gefunden, die ein erstes Argument vom Typ "frm_anforderung_anzeigen" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis


    Wieso kannst du bei dir die Bindingssoruce verwenden und bei mir wirft er einen Fehler?

    Posts zusammengefügt. Zitat korrigiert. ~Thunderbolt

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

    Finde den zu Deinem Projekt relevanten Unterschied.

    Ehm … das tDS und die tDS-BindingSource müssen natürlich auch im Subform existieren. Wenn bindingSource1 nur auf dem Hauptform, aber nicht auf frm_anforderung_anzeigen ist, ergibt die Zeile Dialog.bindingSource1.DataSource = ja keinen Sinn, da Dialog ja vom Typ frm_anforderung_anzeigen ist.
    Dateien
    • WinFormsCS.zip

      (22,47 kB, 15 mal heruntergeladen, zuletzt: )
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.