Entwickler-Ecke
Sonstiges (.NET) - Grundsätzliche Frage zu Modelklassen
Talemantros - Do 10.04.14 09:19
Titel: Grundsätzliche Frage zu Modelklassen
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.
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 - 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 - Do 10.04.14 18:13
Hi,
hinter dem Aufruf verbirgt sich:
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 - 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"
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
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
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
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 - 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
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(); 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.
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 - 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ß
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!