Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
LinQ Abfrage mit Left Join richtig aufbauen
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

LinQ Abfrage mit Left Join richtig aufbauen

beantworten | zitieren | melden

verwendetes Datenbanksystem: <Sql2008R2>
Hallo, ich habe eine Problem mit einer Abfrage in LinQ. Habe in FOren gesucht und auch etwas gefunden. Ich habe drei Tabellen, die alle in einem Dataset eingelesen sind. Jetzt will Tabell1 / Tabelle2 / Tabelle3 miteinander verknüpfen. Tabelle1 ist der Master er hat zu jeder der beiden anderen Tabellen auf jeden Fall einen Datensatz. Tabelle2 oder Tabelle3 habe nicht immer zu jedem Datensatz in Tabelle1 einen Datensatz. Ich möchte also somit eine löchrige Gesamttabelle erstellen (aus den drei Tabellen). Der Bezug ist die Auftragsnummer. Habe da zwei Konstrukte aufgebaut, haber aber das Problem, das beim zweiten Konstrukt beim abrufen der Daten der Compiler auf die Barrikaden geht, sobald in "Mahnliste" oder "Planliste" ein Datensatz nicht vorhanden ist. Da sollen dann einfach die Felder leer bleiben. (Jetzt fällt mir was ein, in den beiden Tabellen "Mahnliste" und "Planliste" sind Spalten, die nicht NULL sein dürfen, kann das evtl. das Problem sein?) Wie gebe ich für solche leere Felder Standardwerte vor?

Hier mal die beiden Konstrukte:



            var test = from move in DsAftVerwalt.Tables["Movedaten"].AsEnumerable()
                        join mahn in DsAftVerwalt.Tables["Mahnliste"].AsEnumerable() on move["Auftragsnr"].ToString().Trim() equals mahn["Auftragsnummer"].ToString().Trim()  into moveMahn
                        join plan in DsAftVerwalt.Tables["Planliste"].AsEnumerable() on move["Auftragsnr"].ToString().Trim() equals plan["Auftragsnummer"].ToString().Trim()  into movePlan

                        from mahn in moveMahn.DefaultIfEmpty()
                        from plan in movePlan.DefaultIfEmpty()


                        select new
                        {
                            Auftragsnummer = move["Auftragsnr"],
                            Maschinengruppe = move["Maschinengruppe"],
                            Mahndatum = mahn["Mahndatum"],
                            Maschine = plan["Maschine"]

                        };


Hier das zweite Konstrukt:


            var test1 = from move in DsAftVerwalt.Tables["movedaten"].AsEnumerable()
                        from mahn in DsAftVerwalt.Tables["Mahnliste"].AsEnumerable().Where(x => x["Auftragsnummer"].ToString().Trim() == move["Auftragsnr"].ToString().Trim())
                        from plan in DsAftVerwalt.Tables["Planliste"].AsEnumerable().Where(y => y["Auftragsnummer"].ToString().Trim() == move["Auftragsnr"].ToString().Trim()).DefaultIfEmpty()

                        select new
                       {
                           Auftragsnummer = move["Auftragsnr"],
                           Maschinengruppe = move["Maschinengruppe"],
                           Mahndatum = mahn["Mahndatum"],
                           Maschine = plan["Maschine"]

                       };

Kann mir da jemand Unterstützung geben?
private Nachricht | Beiträge des Benutzers
DaMoe80
myCSharp.de - Member



Dabei seit:
Beiträge: 508

beantworten | zitieren | melden

Hi!

Dir fehlt im zweiten Konstrukt das kleine, aber wichtige Schluesselwort "into". Das "into" macht bei Linq einen Outer Join aus. Laesst du das "into" weg, ist es ein Inner Join.

Gruss,
DaMoe
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

Linq mit outer join

beantworten | zitieren | melden

Hallo, ich muss mich da langsam hineintatsten. Arbeite als schon mit LinQ, aber nicht so verzwickte Sachen. Ich versuche erst mal so anzufangen. Ich habe die beiden Tabellen mvx und mhn.
In der mvx sind alle Datenzeilen relevant.
In der mhn sind nur ein paar Datensätze vorhanden, Schlüssel zueinander ist die Auftragsnummer.

Jetzt möchte ich eine Abfrage erstellen, mit aalen Datensätzen von Tabelle mvx und den zugeordneten Datensätzen von Tabelle mhn. Ist kein Datensatz von mhn vorhanden, wird ein Default-Datensatz zugewiesen.

Hier mal ein Beispiel, funktioniert aber nicht. Sobald in der mhn ein Datensatz nicht vorhanden ist, streikt die Abfrage. Ich habe jetzt mal nur von jeder Tabelle eine Spalte verwendet.


 var mvx = DsAftVerwalt.Tables["Movedaten"].AsEnumerable();
            var mhn = DsAftVerwalt.Tables["Mahnliste"].AsEnumerable();

            var xx =    from m in mvx orderby m["Auftragsnr"]
                        join p in mhn on m["Auftragsnr"] equals p["Auftragsnummer"] into outer
                        from o in outer.DefaultIfEmpty()
                        select new
                                    {
                                        Auftragsnummer = c["Auftragsnr"], Mahndatum = ((o["Mahndatum"] == DBNull.Value) ? "" : o["Mahndatum"])
                                    };
private Nachricht | Beiträge des Benutzers
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Soweit ich dich verstanden habe, willst du ein LeftOuterJoin machen(?)

Unter Join Operators/Left Outer Join bekommst du ein Beispiel. Dein Code entspricht dem ja relativ genau - allerdings vermute ich stark, dass der Fehler bei dir beim Vergleich o["Mahndatum"] == DBNull.Value liegt. Hier triffst du auf einen Unterschied zwischen SQL und LINQ - denn wenn es keinen Joinpartner gibt, ist schon das o-Objekt null (statt wie in SQL der Wert der Spalte).

Deine Zuweisung musst du also nur auf Mahndatum = (o==null) ? "" : o["Mahndatum"] ändern. Dann sollte es eigentlich gehen.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dN!3L am .
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

LinQ mit 2 Tabelle geht, jetzt noch mit drei Tabellen

beantworten | zitieren | melden

Hi, endlich hats geklappt. Das war der Fehler mit (o==null).

Jetzt kommt noch eine dritte Tabelle dazu, die auch nur ein paar Datensätze hat, aber auch zu jedem Datensatz in Tabelle1 (mvx) eine leere oder wenn Daten vorhanden die Felder gefüllt hergeben muss.

Ich habe das erst mal in eine weitere Query ausgelagert, siehe Code:


var yy =    from m in xx orderby m.m["Auftragsnr"]
                        join p in pln on m.m["Auftragsnr"] equals p["Auftragsnummer"] into outer
                        from o in outer.DefaultIfEmpty()
                        select new
                                    {
                                        //Auftragsnummer = m["Auftragsnr"], Mahndatum = ((o == null) ? "" : o["Mahndatum"])
                                        m,  o
                                    }; 

Wie kann ich das aber in eine Abfrage packen, damit ich dann 3 Rows habe??
private Nachricht | Beiträge des Benutzers
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Zitat von oehrle
Wie kann ich das aber in eine Abfrage packen, damit ich dann 3 Rows habe??
Naja, das erlernte Wissen anwenden und einfach analog zu dem, was du hast, weitermachen.
Hier mal ein abgespecktes Beispiel:


var oneSet =   new[] { new { ID = "1",OneValue = 1 },new { ID = "2",OneValue = 1 },new { ID = "3",OneValue = 1 }, };
var twoSet =   new[] { new { ID = "1",TwoValue = 2 },new { ID = "2",TwoValue = 2 }, };
var threeSet = new[] { new { ID = "1",ThreeValue = 3 }, };

// das hast du ja schon (LeftOuterJoin mit zwei Sequenzen):
var query1 = from one in oneSet
			 join two in twoSet on one.ID equals two.ID into outerTwoSet
			 from outerTwo in outerTwoSet.DefaultIfEmpty()
			 select new { One = one,Two = outerTwo };

// das willst du haben (LeftOuterJoin mit drei Sequenzen):
var query2 = from one in oneSet
			 join two in twoSet on one.ID equals two.ID into outerTwoSet
			 from outerTwo in outerTwoSet.DefaultIfEmpty()
			 join three in threeSet on one.ID equals three.ID into outerThreeSet
			 from outerThree in outerThreeSet.DefaultIfEmpty()
			 select new { One = one,Two = outerTwo,Three = outerThree };

Das ergibt dann folgende Ergebnisse (oben query1, unten query2):
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dN!3L am .
Attachments
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

LinQ mit LeftOuterJoin funktioniert

beantworten | zitieren | melden

Danke dir, habe das gerade vorher getestet und es funzt. Bin erst al guter Laune darüber. Kann ich das in LinQ (also die QUery) auch noch gleich in DataRow[] casten oder sofort in eine DataTable stecken? Wenn ich das nur schon ineinem DataRow[] hätte, wäre das schonalles, dann die Dinge in eien Tabelle schaufeln, oder da gibt es noch etwas mit .Tolist().
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

beantworten | zitieren | melden

Zitat von oehrle
Danke dir, habe das gerade vorher getestet und es funzt. Bin erst al guter Laune darüber. Kann ich das in LinQ (also die QUery) auch noch gleich in DataRow[] casten oder sofort in eine DataTable stecken? Wenn ich das nur schon ineinem DataRow[] hätte, wäre das schonalles, dann die Dinge in eien Tabelle schaufeln, oder da gibt es noch etwas mit .Tolist().

Ich habe heute morgen nochmal getestet. Ich komme da noch nicht zum Ziel. Ich möchte diese Zusmmenfassung der drei Tabellen in eine Tabelle packen, und dann in einem DataGrid darstellen. Dort soll man dann in den Feldern der Tab3 (also Plantabelle) Werte eintragen, welche ich dann durch den RowState "modified" oder "added" erfassen kann und dann diese Änderungen in die Datenbank schreibe.

Ich dachte est mal an so etwas, alle Zeilen in eine DataRow[]-Array zu schreiben, aber da gibt es auch´Probleme mit Spaltentypen:


 IEnumerable<DataRow[]>  query = (IEnumerable<DataRow[]>) (from m in mvx
                                                       orderby m["Auftragsnr"]
                                                       join p in mhn on m["Auftragsnr"] equals p["Auftragsnummer"] into outerMvxMhn
                                                       from omm in outerMvxMhn.DefaultIfEmpty()
                                                       join z in pln on m["Auftragsnr"] equals z["Auftragsnummer"] into outerMvxMhnPln
                                                       from outerPln in outerMvxMhnPln.DefaultIfEmpty()
                                                       select new
                                                                  {
                                                                      //mvx,
                                                                      //outerMvxMhn,
                                                                      outerMvxMhnPln 
                                                                  });

Kann mir da jemand Unterstützung geben? Am besten wäre es wennich die query mit allen drei verjointen Tabellen in einer Tabelle hätte.
private Nachricht | Beiträge des Benutzers
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Zitat von oehrle
Kann ich das in LinQ (also die QUery) auch noch gleich in DataRow[] casten oder sofort in eine DataTable stecken?
Nein, du kannst es nicht casten - denn es ist ja eben kein DataRow-Array (sondern eine Auflistung von Objekten eines anonymen Typs). Allerdings kannst du eine Objekt-Auflistung direkt als Datenquelle eines DataGrids benutzen.
Wenn es dir nützt, kannst du dir auch eine DataTable erstellen und jedes Auflistungselement als DataRow hinzufügen.
Zitat von oehrle
Ich möchte diese Zusmmenfassung der drei Tabellen in eine Tabelle packen und [...] dann durch den RowState "modified" oder "added" [...] diese Änderungen in die Datenbank schreibe.
Möchtest du den RowState direkt in den drei Original-DataTables präsent haben? Also so, dass du in der einen Join-DataTable schreibst und Änderung direkt in die ursprünglichen Tabellen zu sehen sind?
Ich denke, von dem Gedanken kannst du dich verabschieden. Jedenfalls fällt mir keine (hinreichend einfache) Möglichkeit ein, das zu tun.

Soweit ich verstanden habe, was du machen willst, würde ich zu folgendem Vorgehen tendieren:
  1. Du erstellst dir via anonymen Typen eine Auflistung der Elemente deiner Jointabelle.
  2. Diese Auflistung bindest du an ein DataGrid. Änderungen im DataGrid sollten (automatisch) direkt zurück in die Objekte geschrieben werden.
  3. Bei der Speicheroperation musst du alle Objekte durchlaufen (hier bietet sich dann besser auch an, einen konkreten Typen [statt einen anonymen] zu verwenden) und alle Werte zurück in die drei Ursprungs-DataTables schreiben.
  4. Die drei ursprünglichen DataTables sollten nun einen entsprechenden RowState haben und du kannst sie zurückschreiben.
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

LinQ LEft outer Join mit 3 Tabellen aus DataSet

beantworten | zitieren | melden

Ok, werde mich mal versuchen. Das ist wirklich ein blödes PRoblem, an dem ichda schon seit mitte der Woche dran hänge. Nochmal zum Verständnis: Die Daten der drei Tabellen ergänzen sich zu einem Auftragsüberblick. Tab1 hat die Werkzeugdaten, Tab2 die Mahndaten, Tab3 die Planungsdaten für Abarbeitung. Alle drei Tabellen sind über die Spalte Auftragsnummer zueinander zu verknüpfen. Bei Tab2 und Tab3 kann es sein, das es noch keinen Datensatz zu Tab1 gibt. Diese Datensätze müssen dann aber auch angezeigt werden. Der user kann dann noch über eine Filtermaske seine genauen AUftagsbereiche filtern, und dann in die Spalten der Tab3 die Daten für die geplante Bearbeitung eintragen. Nur diese geänderte oder neu eingetragenen Daten der Tab3 werde zurückgespeichert. Das alles wäre dann am besten in einem DataGrid darzustellen. Ich tu mir da gerade echt schwer. Also versteht man das was ich vorhabe, oder muss ich das nochmal besser schildern?
private Nachricht | Beiträge des Benutzers
oehrle
myCSharp.de - Member



Dabei seit:
Beiträge: 413
Herkunft: Germany

Themenstarter:

Problem beim internen casten? Warum?

beantworten | zitieren | melden

Kann mir jemand einen Tipp geben? Habe bei MS etwas gefunden, was ich anwenden wollte, aber beim abrufen der Daten bekomme ichden Fehler: "SPecifies cast is not valid"

Habe aber die Spaltentypen wie bei den DB-Tabellen angegeben.

Hier mal der Code , evtl. hat jemand eine Idee oder sieht den Fehler sofort (kann man das irgedwie debuggen??):




           var mvx = DsAftVerwalt.Tables["Movexdaten"].AsEnumerable();
            var mhn = DsAftVerwalt.Tables["Mahnliste"].AsEnumerable();
            var pln = DsAftVerwalt.Tables["Planliste"].AsEnumerable();


            //// Für Default-Row in LinQ
            DataRow dRowMahn = DsAftVerwalt.Tables["Mahnliste"].NewRow();
            dRowMahn[1] = 0;
            dRowMahn[2] = "0000";
            dRowMahn[3] = "0000";
            dRowMahn[4] = DateTime.Now;


 var xxx = from m in mvx
                      orderby m.Field<Decimal>("Auftragsnr")
                      join p in mhn on m.Field<Decimal>("Auftragsnr") equals p.Field<Decimal>("Auftragsnummer") into outer
                      from o in outer.DefaultIfEmpty(dRowMahn)
                      select new
                                 {
                                     Auftragsnr = m.Field<Decimal>("Auftragsnr"),
                                     Maschinengruppe = m.Field<String>("Maschinengruppe"),
                                     AGStatus = m.Field<String>("AGStatus"),
                                     AGBeschreibung = m.Field<String>("AGBeschreibung"),
                                    Mahndatum = o.Field<DateTime>("Mahndatum")
                     };
private Nachricht | Beiträge des Benutzers
dN!3L
myCSharp.de - Experte

Avatar #avatar-2985.png


Dabei seit:
Beiträge: 3138

beantworten | zitieren | melden

Zitat von oehrle
Kann mir jemand einen Tipp geben?
Ich habe dir doch schon geschrieben, wie ich es machen würde.
Zitat von oehrle
kann man das irgedwie debuggen??
Wie du selbst Programme mit der Entwicklungsumgebung deiner Wahl debuggst, solltest du schon wissen (Haltepunkte, Überwachungsfenster, schrittweise Ausführung usw. sind eigentlich Grundlagen).
Falls wir da was für dich debuggen sollten: [Tutorial] Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden
private Nachricht | Beiträge des Benutzers