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

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 10.04.14 09:19 
Hi zusammen,
da ich nun ja einiges zu Modellklassen etc. gelernt habe stelle ich mir aber für den weitere Verlauf noch eine Frage:

1.) Wann nutze ich Modellklassen? Macht es immer Sinn eine Modellklasse mit Properties zu "hinterlegen"

Beispiel ich habe eine lokaleDB gebastelt als Changelog und Form, welches ein UserControl enthält zum anzeigen der Changelog Daten in einem Gridview

Um die Versionsdaten zu holen rufe ich über eine Combobox eine Methode einer anderen Klasse auf, die mir ein DataTable zurückliefert.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
            DataTable datenbank = new DataTable();
            datenbank = LocalDbQuery.GetChangeLog(connStr, cmbVersion.SelectedItem.ToString());

            dgvChangelog.DataSource = datenbank;

            SetHeader();


Hätte hier jetzt auch eine Modellklasse mit Properties Sinn gemacht?

Danke

Gruß
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 10.04.14 12:28 
Der Sinn läßt sich natürlich nicht wirklich aus einem einzelnen Codeversatzstück lesen.

Wenn der Code funktioniert ist die erste Hürde erstmal genommen. Ob die Lösung Sinn macht ergibt sich erst aus dem ganzen.
Ziel einer Architektur wie die Trennung der Anwendung in Schichten mit eindeutigen Modellen und Interfaces dazwschen ist es insbesondere das sich bestimmte Lösungsmuster immer wiederholen so das ein Lerneffekt beim Benutzer (denke dir einen andere Programmierer) eintritt.

Ein Benutzer der die Daten deiner Anwendung benutzen möchte um zum Beispiel dazu eine UI bereitzustellen sollte also nur die Programmieroberfläche der Datenschicht kennen und nicht (oder nicht zwingend) die Interna. Wenn er Daten einmal als Modelklasse, einmal als DataTable und andere Dinge noch auf irgendeine andere Weise bekommt sollte der sich wundern und wäre immer gezwungen erstmal rauszufinden wie es geht da er es nicht so machen kann wie ~immer~. Wenn du also von möglichen anderen Benutzern, einen Programmierteam oder zumindest von einer gewissen Wartbarkeit des Codes ausgehst (Der andere Benutzer könntest z.B. auch du in 5 Jahren sein der keine Ahnung mehr hat was er sich damals gedacht hat). Aus dieser Sicht würde es also Sinn machen bestimmte Muster durchzuziehen auch wenn es im Einzelfall erstmal nach mehr Aufwand aussieht. Wenn das aber eine Einweg-Wegwerfanwendung ist oder nur tatsächlich von dir, für dich und /oder der Lerneffekt egal ist dann macht es keinen Sinn da mehr Aufwand reinzustecken.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 10.04.14 18:13 
Hi,

hinter dem Aufruf verbirgt sich:

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 GetChangeLog(string connStr, string versionsnummer)
        {
            DataTable datenbank = new DataTable();
            try
            {
                SqlConnection conn = new SqlConnection(connStr);

                string strSQL = "SELECT bereich, art, beschreibung from tblChangelog where version=@versionsnummer";

                SqlDataAdapter da = new SqlDataAdapter(strSQL, conn);

                da.SelectCommand.Parameters.AddWithValue("@versionsnummer", versionsnummer);

                da.Fill(datenbank);

                return datenbank;
            }
            catch (Exception)
            {
                MsgAusgabe.ShowError("Beim Auslesen der Daten ist ein Fehler aufgetreten!");
                throw;
            }
        }


Also wenn ich ehrlich bin hatte ich schon überlegt es alles einheitlich zu machen mit einer Modellklasse, bin dann aber irgendwie daran gescheitert, dass bei der ersten Modellklasse die ich mit eurer Hilfe gebaut hatte immer nur eine TextBox einen Wert gelesen und gesetzt hat.

Hier wäre es ja eine Liste und irgendwie kam ich da nicht weiter.
Dann kam ich auf die umgesetzte Idee und habe mich im Umkehrschluß dann gefragt wann ich eigentlich die Modellklasse nutzen sollte.


Werde versuchen im Netz noch einiges an Dokus oder so zu Modellklassen mit Listen zu finden.

Danke schonmal

Gruß

EDIT:
Ich hatte jetzt am Wochenende wenig Zeit und kann mich erst heute und morgen wieder ein wenig um C# kümmern.

Wäre der Ansatz den ich hier genannt hatte ok?
Ansonsten habe ich mal ein wenig gelesen und eine weiter Möglichkeit wäre eine Modellklasse zum Changelog zu machen und dann eine Klasse die eine Liste zurück liefert an die Anwendung mit den entsprechenden Datensätzen gefüllt durch einen DataReader?!

Wenn ihr dies als sinniger erachten würdet um eine Gleichmäßigkeit zu haben würde ich mich daran mal versuchen?!
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Mo 14.04.14 19:24 
Hi,
habe nun mal alles umgebaut, so dass ich eine Modellklasse habe und entsprechend mit dieser arbeite.
Ich würde mich über konstruktive Kritik sehr freuen.

Modellklasse "ChangeLog"

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:
24:
25:
26:
27:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LocalDbConnect
{
    public class ChangeLog
    {
        public ChangeLog()
        {

        }

        public ChangeLog(string bereich, string art, string beschreibung)
        {
            this.Bereich = bereich;
            this.Art = art;
            this.Beschreibung = beschreibung;
        }

        public string Bereich { get; set; }
        public string Art { get; set; }
        public string Beschreibung { get; set; }
    }
}


Methode für die Modellklasse

ausblenden volle Höhe 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:
56:
57:
58:
using MsgBox;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LocalDbConnect
{
    public class ChangeLogMethods
    {       
        public static List<ChangeLog> GetChangeLog(string connStr, string versionsnummer)
        {
            List<ChangeLog> neuChange = new List<ChangeLog>();

            string strSQL = "SELECT bereich, art, beschreibung from tblChangelog where version=@versionsnummer";

            using (SqlConnection conn = new SqlConnection (connStr))
            {
                try
                {
                    conn.Open();
                    
                    SqlCommand cmd = new SqlCommand(strSQL, conn);
                    cmd.Parameters.AddWithValue("@versionsnummer", versionsnummer);
                    
                    SqlDataReader dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        ChangeLog einChange = new ChangeLog();
                        einChange.Bereich = dr["bereich"].ToString();
                        einChange.Art = dr["art"].ToString();
                        einChange.Beschreibung = dr["beschreibung"].ToString();

                        neuChange.Add(einChange);                           
                    }

                }
                catch (Exception ex)
                {
                    MsgAusgabe.ShowError(ex.Message);
                    throw;
                }
                finally
                {
                    if (conn.State == System.Data.ConnectionState.Open)
                    {
                        conn.Close();
                    }
                }
            }

            return neuChange;
        }
    }
}


Aufruf aus der USerControl

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
        private void cmbVersion_SelectedIndexChanged(object sender, EventArgs e)
        {
            List<ChangeLog> change = new List<ChangeLog>();
            change = ChangeLogMethods.GetChangeLog(connStr, cmbVersion.SelectedItem.ToString());

            dgvChangelog.DataSource = change;

            SetHeader();
        }


SetHeader für DataGridView

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
        private void SetHeader()
        {
            dgvChangelog.Columns[0].HeaderText = "Bereich";
            dgvChangelog.Columns[1].HeaderText = "Art";
            dgvChangelog.Columns[2].HeaderText = "Beschreibung";
        }
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 14.04.14 21:30 
a.) Für die SQL Komponenten solltest du immer den using Syntax verwenden so das die von der Klassen verwendeten Resourcen sofort freigegeben werden wenn der using Block verlassen wird. Das solltest du eigentlich immer tun bei Klassen die IDisposable implementieren.
b.) Du solltest in dem Code Richtung Datenbank nichts verwenden das ein Bezug zur UI hat. Das schränkt sonst die Nutzbarkeit der Klasse extrem ein. In GetChangeLog sollte also keine MessageBox benutzt werden oder etwas das einer MessageBox entspricht. Wenn eine Visualisierung gewünscht ist sollte die erst da erfolgen wo der Code eindeutig der UI zuzuordnen ist. Dort solltest du dann einen Try catch haben. Da kannst du dann auch eher rausfinden ob man hier normal weitermachen kann oder tatsächlich die Exception weiterwerfen muss. So wie das jetzt aussieht würde ich erwarten das dir ein Fehler mehrmals gemeldet wird. Aus GetChangeLog und an einer späteren Stelle wo die Exception die du ja weiterwirfst auch gefangen wird.

In Summe ergibt das etwa

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public static DataTable GetChangeLog(string connStr, string versionsnummer)
{
    DataTable datenbank = new DataTable();
    using (SqlConnection conn = new SqlConnection(connStr))
    {
        conn.Open(); // Kann man sich das bei einem Adapter sparen? Du öffnest die Connection zumindest nicht in deinem Code. 
        using (SqlDataAdapter da = new SqlDataAdapter("SELECT bereich, art, beschreibung from tblChangelog where version=@versionsnummer", conn))
        {
            da.SelectCommand.Parameters.AddWithValue("@versionsnummer", versionsnummer);
            da.Fill(datenbank);
        }
    }
    return datenbank;
}


Das in die Methode der Connectionstring reingeht hat zumindest ein gewisses Geschmäckle. Ich kann da gerade nix empfehlen aber es fühlt sich falsch an.

Deine cmbVersion_SelectedIndexChanged erzeugt eine List<string> zuviel. Die würde sofort wieder von der aus GetChangeLog zurückgegebenen überschrieben werden. Und wo wir schon dran sind kann man die unnötige Variable dann gleich ganz auflösen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
private void cmbVersion_SelectedIndexChanged(object sender, EventArgs e)
{
   dgvChangelog.DataSource = ChangeLogMethods.GetChangeLog(connStr, cmbVersion.SelectedItem.ToString());
   SetHeader();
}
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 17.04.14 10:19 
Hallo,
ich hatte die letzten Tage wenig Zeit leider, konnte nun aber deine Anregungen umsetzen und bin das Projekt soweit durchgegangen, dass ich alle MsgBoxen aus der Datenbanbankebene genommen habe und die unnötige Listvariablen entfernt habe.

Vielen Dank

Gruß