Autor Beitrag
Talemantros
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Mi 22.04.15 10:47 
Hi,
ich habe hier www.entwickler-ecke....ataTable_114206.html ein DataTable, in welchem der Benutzer sich Daten aus dem DGV auswählen kann.

Anhand dieser Auswahl möchte ich nun ein neues DataTable mit anderen Informationen zusammenstellen, welches ich an den Vordruck übergeben will.

Das DataTable welches der Benutzer zur Auswahl hat:
ausblenden C#-Quelltext
1:
2:
3:
4:
                //DataTable aus der BindingSource generieren für alle markierten Zeilen
                DataTable dt = (bsOktabiner.DataSource as DataTable).Clone();
                foreach (DataGridViewRow row in dgvUebersicht.SelectedRows)
                    dt.ImportRow((row.DataBoundItem as DataRowView).Row);


Anhand der Auswahl ein neues DataTable erstellen:


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
                DataTable dtPackliste = new DataTable();

                //Beginn Packliste
                foreach (DataRow row in dt.Rows)
                {
                    dtPackliste.Rows.Add(TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight((long)row[0]));
                }


Leider bemängelt er mir hier, dass das Eingabearray anders ist wie die Anzahl der Spalten, die geliefert werden.

Wenn ich es wie folgt ändere funktioniert es.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
                DataTable dtPackliste = new DataTable();
                dtPackliste.Columns.Add("ID");
                dtPackliste.Columns.Add("Material");
                dtPackliste.Columns.Add("lagerplatz");
                dtPackliste.Columns.Add("Gewicht");

                //Beginn Packliste
                foreach (DataRow row in dt.Rows)
                {
                    dtPackliste.Rows.Add(TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight((long)row[0]));
                }


Nur möchte ich nicht, dass ich die Spalten mitliefern muss.
Jetzt habe ich verscuht mit der Clone Methode weiter zu kommen, bisher aber ohne Erfolg.

Sollte ich eine BindingSource dazwischen hängen und eine Abfrage auf die Datenbank machen, die "leer" zurück kommt und dann die HEader übernehmen?
Klingt für mich erstmal so, als ob dies auch anders geht und ich weiß nur nicht wie :-)

Könnt ihr mir helfen?

Danke

VG

EDIT:
Gerade festgestellt, dass DataTable leer ist :-(
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 22.04.15 11:35 
dtPackliste braucht auf jeden Fall eine Spaltendefinition ganz ohne wird das immer knallen. Entweder du definierst die oder du bekommst die von der Datenbank.

Was macht GetDataTableIDCrapStockPlaceWeight eigentlich? Liefert die eine DataTable, DataRow oder ein Object Array? Sie heißt GetDataTable sie liefert aber bestimmt keine DataTable, dann würde dein Code nicht kompilieren. Bitte in den Bezeichner von Methoden und Variablen nicht lügen du stellst dir nur selbst ein Bein damit. Wenn die Methode Daten aus der Datenbank zu einer übergebenen ID sammelt würde ich die IDs deiner Quell DataTable erstmal sammeln und in einem Rutsch an die die Methode geben und diese wiederum wenn möglich auch in einem Rutsch an die Datenbank senden so das es auch nur eine Abfrage gibt. Diese eine Abfrage würde dann auch ganz nebenbei die Spaltendefintion mitliefern was so jetzt nicht klappt da du ja scheinbar DataRow rüber kopierst und die haben keine Spaltendefinition die hat nur die DataTable.

Dann sähe der Aufruf der Methode so aus
ausblenden C#-Quelltext
1:
DataTable dtPackliste = TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight(dt.AsEnumerable().Select(row=> x[0]));					

Deren Signatur
ausblenden C#-Quelltext
1:
public static DataTable GetDataTableIDCrapStockPlaceWeight(IEnumerable<long> ids)					


intern dann die ids zu einer StringListe zusammenfassen und dem Select für die Datenabfrage als IN Klausel übergeben.


Zuletzt bearbeitet von Ralf Jansen am Mi 22.04.15 12:01, insgesamt 1-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 22.04.15 11:41 
Hallo Talemantros,

die DataTable.Clone-Methode benutzt du doch schon in deinem ersten Code.
Also einfach:
ausblenden C#-Quelltext
1:
DataTable dtPackliste = dt.Clone();					
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Mi 22.04.15 12:17 
Hallo Ralf,
Im Moment liegt hinter der Methode GetDataTable folgendes:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
        public static DataTable GetDataTableIDCrapStockPlaceWeight(long oktabiner)
        {
            strSQl = "Select oktnummer, schrottart, netto, lagerplatz.nummer "
                    + "from oktabinergrund "
                    + "left join oktabinerinhalt on oktabinerinhalt.oktabinergrundid = oktabinergrund.oktabinergrundid "
                    + "left join bestand on bestand.bestandid = oktabinerinhalt.bestandid "
                    + "left join schrottart on schrottart.schrottartid=bestand.schrottartid "
                    + "left join lagerplatz on lagerplatz.lagerplatzid=oktabinergrund.lagerplatzid "
                    + "where oktabinergrund.oktabinergrundid=?oktabinergrundid ";

            DataTable dt = new DataTable();

            using (MySqlConnection conn = new MySqlConnection(connStr))
            {
                using (MySqlDataAdapter da = new MySqlDataAdapter(strSQl, conn))
                {
                    da.SelectCommand.Parameters.AddWithValue("?oktabinergrundid", oktabiner);
                    da.Fill(dt);
                }
            }

            return dt;
        }


Also aus meiner Sicht schon eine DataTable, deswegen hatte ich die so genannt.

Den Anfang und deinen Ansatz verstehe ich. Leider nicht was du am Ende meinst mit

Zitat:


intern dann die ids zu einer StringListe zusammenfassen und dem Select für die Datenabfrage als IN Klausel übergeben.


Kannst du auf den zusammenfassen und die IN Klausel noch mal eingehen?

@th69
Das habe ich als verscuht, aber ich Idiot habe es nicht auf die dt selber versucht. Argh. Ich habe als die Methode umklammert und versucht zu clonen.

Danke an euch.

Vg

EDIT: Jetzt hänge ich ganz.
Den Eintrag von Ralph verstehe ich noch nicht und wenn ich mit dem Vermerk von TH69 erstmal weiter machen wollte macht er dies auch nicht

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
                DataTable dtPackliste = dt.Clone();

                //foreach (DataRow row in dt.Rows)
                //{
                //    dtPackliste.Rows.Add(TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight((long)row[0]));
                //}
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 22.04.15 13:53 
Zitat:
Also aus meiner Sicht schon eine DataTable, deswegen hatte ich die so genannt.

Du schiebst die aber in eine Row rein. Ich hätte zuerst gedacht das würde eine Exception auslösen. Aber logischerweise (technisch) geht das. Es macht nur trotzdem keinen Sinn weil du so eine DataTable annimnst mit einer Spalte in der jede Zelle wieder eine DataTable ist :eyecrazy:

Das mit allen Daten in einem Rutsch holen hatte ich mir so vorgestellt.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
public static DataTable GetDataTableIDCrapStockPlaceWeight(IEnumerable<long> oktabinerIds)
{
    strSQl = @"Select oktnummer, schrottart, netto, lagerplatz.nummer 
                 from oktabinergrund 
                        left join oktabinerinhalt on oktabinerinhalt.oktabinergrundid = oktabinergrund.oktabinergrundid 
                        left join bestand on bestand.bestandid = oktabinerinhalt.bestandid 
                        left join schrottart on schrottart.schrottartid=bestand.schrottartid 
                        left join lagerplatz on lagerplatz.lagerplatzid=oktabinergrund.lagerplatzid "
;

    if(oktabinerIds == null || oktabinerIds.Count() == 0)
        strSQl += " where 1 = 0"// keine Daten aber Metainfo holen
    else
    {
        // du solltest für deine DB prüfen wie lang die Liste in einem IN sein darf udn ob du da sinnvoll an die Grenze stößt
        String ids = String.Join(", ", oktabinerIds);
        strSQl += string.Format(" where oktabinergrund.oktabinergrundid in ({0})", ids);
    }
 
 
 ...
}


Das mit dem clonen macht nur Sinn wenn die die gleichen Spalten haben sollen aber ich gehe schwer davon aus das die hier nicht mehr gleich sind richtig? Bei deinem ersten gezeigten Code geht es ja ums Filtern da bleibt die Struktur gleich da macht clonen sind. Jetzt versuchst du aber scheinbar andere Dtaen zur gleichen Id zu holen und da hilft clonen nicht weiter.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Mi 22.04.15 19:30 
Hi, du hast natürlich recht mit deiner Vermutung, dass das Clonen kein Sinn macht.
Habe ich so nicht drüber nachgedacht.

Den Rest habe ich schon mal an getestet und scheint zu funktionieren.
Tollerweise noch 2-3 Kleinigkeiten dazu gelernt bei String und das @ bei SQL String.

Vielen Dank

Gruß
Daniel
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 23.04.15 08:31 
Guten Morgen,
nachdem ich gestern die SQL Syntax an der HeidiSQL getestet hatte, dachte ich es geht alles.
Jetzt habe ich das in C# eingebaut und jetzt bemängelt er etwas.
Da dieser Bereich für mich ganz neu ist/war habe ich da gerade keine Idee wie ich was testen könnte

ausblenden C#-Quelltext
1:
                DataTable dtPackliste = TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight(dt.AsEnumerable().Select(row => x[0]));					


Fehlermeldung:

Der Name "x" ist im aktuellen Kontext nicht vorhanden.

Wenn ich das richtig sehe, ist dies doch eine "neuere" Schreibweise eines Delegaten!? Ich habe nur kein Plan wie ich damit umgehen muss.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 23.04.15 08:52 
Ralf wollte dich wohl testen ;-)

Wenn die Lamda-Variable row heißt, wie muß dann der Zugriff darauf aussehen?
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 23.04.15 09:03 
Hi ;-)
Habe es jetzt in
ausblenden C#-Quelltext
1:
Select(row => row[0]));					
umgeschrieben

Jetzt kommt der nächste Fehler:

Konvertierung von 'System.Data.EnumerableRowCollection<object>' in 'System.Collections.Generic.IEnumerable<long>' nicht möglich.

Den schaue ich mir jetzt mal an.
Danke

EDIT:
Habe es jetzt so geändert
ausblenden C#-Quelltext
1:
                DataTable dtPackliste = TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight((IEnumerable<long>)dt.AsEnumerable().Select(row => row[0]));					


Kompiliert wird es. Ich schaue mal ob es seinen Dienst erfüllt :-)

EDIT2:
Fehler: Das Objekt des Typs "System.Data.EnumerableRowCollection`1[System.Object]" kann nicht in Typ "System.Collections.Generic.IEnumerable`1[System.Int64]" umgewandelt werden.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 23.04.15 10:00 
Zitat:
Ralf wollte dich wohl testen ;-)


Ja genau .... ok ich hab das eher aus dem Lameng geschrieben und nicht ausprobiert :oops:

Bei einem Lambda Ausdruck wird der Rückgabetyp aus dem Kommando deduziert und ich glaube der Indexer für die Werte in der Row liefert einfach object. Wenn du weißt das in Spalte null immer ein long ist dann caste die Spalte eben auf long.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 23.04.15 11:02 
Hallo Ralf,
das hatte ich auch schon probiert.
ausblenden C#-Quelltext
1:
                DataTable dtPackliste = TemplateMethodsIntern.GetDataTableIDCrapStockPlaceWeight((long)dt.AsEnumerable().Select(row => row[0]));					

Mit mässigem Erfolg:

Fehler 3 Argument '1': Konvertierung von 'long' in 'System.Collections.Generic.IEnumerable<long>' nicht möglich.

Daher danach der Versuch mit (IEnumerable<Long>)

Bin bisher nicht weiter gekommen. Hatte Dienstbesprechung und probiere es jetzt weiter.

VG
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4701
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 23.04.15 11:09 
Das einzelne Element in der Liste mußt du casten nicht die Liste.

ausblenden C#-Quelltext
1:
row => (long)row[0]));					
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 23.04.15 14:22 
Vielen Dank