Entwickler-Ecke

WinForms - Objekte in DataTable einlesen


ottto - Fr 13.09.19 11:17
Titel: Objekte in DataTable einlesen
Hallo zusammen,
ich hab eine Frage zum objektorientiertem Aufbau meines Programms.
Meine DataTable wird mit Daten aus einer XML-Datei gefüllt.
Dabei sehe ich jetzt zwei Möglichkeiten die Elemente der XML-Datei in meine DataTable zu schreiben.
Die erste geht, meiner Meinung nach, an der Objektorientierung vorbei, indem ich die ausgelesenen Daten direkt dt.Rows.Add(e1, e2, d1, d2, bs, lio) in die dt schreibe.

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:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
        private void ButXMLEinlesen_Click(object sender, EventArgs e)
        {
            if (!File.Exists(qDatei))
            {
                MessageBox.Show("Datei " + qDatei + " gibt es nicht!!!");
                return;
            }
            string e1 = "!!!";
            string e2 = "!!!";
            string d1 = "!!!";
            string d2 = "!!!";
            string bs = "!!!";
            DateTime lio = new DateTime();

            XmlReader xr = XmlReader.Create(qDatei);
            while (xr.Read())
            {
                if (xr.NodeType == XmlNodeType.Element)
                {
                    switch (xr.Name)
                    {
                        case "eng1":
                            e1 = xr.ReadString();
                            break;
                        case "eng2":
                            e2 = xr.ReadString();
                            break;
                        case "deu1":
                            d1 = xr.ReadString();
                            break;
                        case "deu2":
                            d2 = xr.ReadString();
                            break;
                        case "beispielsatz":
                            bs = xr.ReadString();
                            break;
                        case "letzterIO":
                            lio = Convert.ToDateTime(xr.ReadString());

                            dt.Rows.Add(e1, e2, d1, d2, bs, lio);
                            //Vokabeln.Add(new Vokabel(e1, e2, d1, d2, bs, lio));
                            break;
                    }
                }
            }
            xr.Close();
        }


Bei der zweiten lese ich Objekte aus der XML-Datei und schreibe diese Vokabeln.Add(new Vokabel(e1, e2, d1, d2, bs, lio)) in eine Liste. Danach lese ich diese Liste mit foreach und schreibe die Daten dann erst in meine DT.


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:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
        List<Vokabel> Vokabeln = new List<Vokabel>();

        private void ButXMLEinlesen_Click(object sender, EventArgs e)
        {
            if (!File.Exists(qDatei))
            {
                MessageBox.Show("Datei " + qDatei + " gibt es nicht!!!");
                return;
            }
            string e1 = "!!!";
            string e2 = "!!!";
            string d1 = "!!!";
            string d2 = "!!!";
            string bs = "!!!";
            DateTime lio = new DateTime();

            XmlReader xr = XmlReader.Create(qDatei);
            while (xr.Read())
            {
                if (xr.NodeType == XmlNodeType.Element)
                {
                    switch (xr.Name)
                    {
                        case "eng1":
                            e1 = xr.ReadString();
                            break;
                        case "eng2":
                            e2 = xr.ReadString();
                            break;
                        case "deu1":
                            d1 = xr.ReadString();
                            break;
                        case "deu2":
                            d2 = xr.ReadString();
                            break;
                        case "beispielsatz":
                            bs = xr.ReadString();
                            break;
                        case "letzterIO":
                            lio = Convert.ToDateTime(xr.ReadString());

                            //dt.Rows.Add(e1, e2, d1, d2, bs, lio);
                            Vokabeln.Add(new Vokabel(e1, e2, d1, d2, bs, lio));
                            break;
                    }
                }
            }
            xr.Close();

            foreach (Vokabel v in Vokabeln)
            {
                dt.Rows.Add(v.eng1, v.eng2, v.deu1, v.deu2, v.beispielsatz, v.letzerIO);
            }

        }


Welche Lösung sollte ich verwenden oder gibt es eine bessere? Gibt es bei der zweiten eine Möglichkeit die Liste einzusparen?

Hier noch die Definition der DataTable und der Vokabel:

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:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
        public DataTable dt = new DataTable("Vokabelliste");

        private void FormStart_Load(object sender, EventArgs e)
        {
            dt.Columns.Add("Eng1", System.Type.GetType("System.String"));
            dt.Columns["Eng1"].AllowDBNull = false//Spalte muss gefüllt sein.
            //dt.Columns["Eng1"].Unique = true; //Inhalt darf nicht doppelt sein
            dt.Columns.Add("Eng2", System.Type.GetType("System.String"));
            dt.Columns.Add("Deu1", System.Type.GetType("System.String"));
            dt.Columns["Deu1"].AllowDBNull = false;
            dt.Columns.Add("Deu2", System.Type.GetType("System.String"));
            dt.Columns.Add("Beispielsatz", System.Type.GetType("System.String"));
            dt.Columns.Add("iO gelöst", System.Type.GetType("System.DateTime"));
            dt.Columns["iO gelöst"].ReadOnly = true;
            //dt.Rows.Add("read", "", "lesen", "" , "BeispielSatz!!!", new DateTime(1999, 02, 02));
        }

    class Vokabel
    {
        public readonly string eng1;
        public readonly string eng2;
        public readonly string deu1;
        public readonly string deu2;
        public readonly string beispielsatz;
        public readonly DateTime letzerIO;

        public Vokabel(string e1, string e2, string d1, string d2, string bs, DateTime lio)
        {
            eng1 = e1;
            eng2 = e2;
            deu1 = d1;
            deu2 = d2;
            beispielsatz = bs;
            letzerIO = lio;
        }    
    }



Danke.
Gruß.
ottto

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Th69 - Sa 14.09.19 10:06

Egal ob du die Daten zuerst in eine Liste einliest oder aber direkt in eine DataTable, du solltest aber die Methode aus der Form-Klasse auslagern (=> Datenzugriffsschicht).

Deine zweite Methode ohne die Liste entspricht doch dann deiner ersten Methode?!

Die generelle Frage lautet eher: Ist die DataTable wirklich die beste Struktur oder wäre nicht doch List<Vokabel> besser geeignet, um damit im Programm weiterzuarbeiten?

PS: Statt der public readonly-Variablen (in class Vokabel) benutzt man eigentlich besser (Nur-Lese) Eigenschaften dafür:

C#-Quelltext
1:
public string Eng1 { get; } // und der C#-Namenskonvention entsprechend mit großem Anfangsbuchstaben                    


ottto - Mo 16.09.19 16:27

Vielen Dank für die Tipps. Welche Klasse macht den meisten Sinn, zum Auslagern der Methode?
Gehört sowas in die class Vokabeln oder eher in die class Program?
Danke.
Gruß.
ottto


Ralf Jansen - Mo 16.09.19 16:44

Zitat:
Gehört sowas in die class Vokabeln oder eher in die class Program?

Weder noch. Es gehört in eine 3.te Klasse in der du den Code zum Einlesen der xml (und alles was vielleicht später noch dazu kommt) verlagerst und dir eine List<Vokabel> rausrückt.

Moderiert von user profile iconTh69: C#- durch Quote-Tags ersetzt


ottto - Mo 16.09.19 16:55

Die geänderte Liste würde dann auch wieder in eine Datei gespeichert werden.
Gehört dies dann mit in diese Klasse oder sollte das dann wieder in eine eigene?
Danke.
Gruß.
ottto


Th69 - Mo 16.09.19 20:26

Das kommt wohl auf den Umfang der Methoden an. Bei nur zwei Hauptmethoden würde eine Klasse mit den beiden Methoden Load und Save ausreichen (alternativ zwei Klassen, z.B. VocableReader und VocableWriter).

Hier noch zwei Links zur sogenannten 3-Schichten-Architektur (da dir das anscheinend noch unbekannt ist):
HowTo: 3-Tier / 3-Schichten Architektur [https://blog.codeinside.eu/2008/07/09/howto-3-tier-3-schichten-architektur/]
Wie funktioniert die 3-Schichten-Architektur? [http://www.mrknowing.com/2013/11/08/wie-funktioniert-die-3-schichten-architektur/]