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
Datenlisten immer nach gleichem Schema erstellen
Jessimaus
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

Datenlisten immer nach gleichem Schema erstellen

beantworten | zitieren | melden

Hallo Leute,

habe gerade gesehen, dass man hier eigene Programme oder Teile davon zur 'Begutachtung' bzw. Diskussion vorstellen kann.
Ich benötige in unserem Projekt etliche Listen, so dass ich die immer nach dem gleichen Schema erstellen möchte.
Ich habe mich weitgehend an der Vorgehensweise im Doberenz orientiert.
Die unten beispielhaft angeführte Klasse LstArtikel würde ich dann als Basisklasse für DtoArtikel verwenden wollen,
die um die Bearbeitungsfunktionen Insert, Update und Delete erweitert ist.

Wie man schnell sieht, ist es nichts kompliziertes aber vielleicht gibt es ja den einen oder anderen hilfreichen Hinweis oder gar grundsätzliche Einwände.
Beispielsweise bin ich nicht sicher, ob das using nicht besser durch einen try/catch-Block ersetzt werden sollte.

Ich freue mich auf eure Kommentare
Liebe Grüße Jessimaus


#region using-Anweisungen
	using System;
	using System.Collections.ObjectModel;
	using System.Data;
	using System.Data.SqlClient;
	using System.Globalization;
	using Model.POCO;
	using Model.POCO.Database;
#endregion
namespace ViewModel.Lists{
	public class LstArtikelstamm : Collection<Artikelstamm>{

		private readonly	SqlConnection _SqlCon;
		private readonly	int _MandantenID;
		private const string COMMANDTEXT =
			@"SELECT * FROM [dbo].[ilfSelectArtikelliste](@MandantenID)";

		public LstArtikelstamm(MdbConnection MdbCon){
			if(MdbCon == null) return;

			_SqlCon		= MdbCon.SqlCon;
			_MandantenID	= MdbCon.MandantenID;
			fill_Liste();
		}	// End Konstruktor

		private void fill_Liste(){
			using(var _SqlReaderCommand = POCOModelBase.get_SqlCommand()){
				if(_SqlReaderCommand == null) return;

				_SqlReaderCommand.Connection	= _SqlCon;
				var _DrPrmMandantenID = new SqlParameter("@MandantenID", SqlDbType.Int){
					Direction = ParameterDirection.Input
				};
				_SqlReaderCommand.Parameters.Add(_DrPrmMandantenID);
				_SqlReaderCommand.CommandText = COMMANDTEXT;
				if(_SqlCon.State != ConnectionState.Open){
					_SqlCon.Open();
				}
				Clear();
				_SqlReaderCommand.Parameters[0].Value = _MandantenID;
				using(var _Reader = _SqlReaderCommand.ExecuteReader(CommandBehavior.CloseConnection)){
					if(!_Reader.HasRows) return;

					while(_Reader.Read()){
						var Listenartikel = new Artikelstamm{
							MandantenID	= _MandantenID,
							ArtikelID	= Convert.ToString(_Reader["ArtikelID"], CultureInfo.CurrentCulture),
							Artikelname	= Convert.ToString(_Reader["Artikelname"], CultureInfo.CurrentCulture),
							SteuersatzID	= Convert.ToInt32(_Reader["SteuersatzID"], CultureInfo.CurrentCulture),
							KategorieID 	= Convert.ToInt32(_Reader["KategorieID"], CultureInfo.CurrentCulture),
							GruppenID	= Convert.ToInt32(_Reader["GruppenID"], CultureInfo.CurrentCulture),
							Bearbeiter	= Convert.ToString(_Reader["Bearbeiter"], CultureInfo.CurrentCulture),
							LetzteAenderung	= Convert.ToDateTime(_Reader["LetzteAenderung"], CultureInfo.CurrentCulture),
							Zeilenversion	= _Reader.GetFieldValue<byte[]>(_Reader.GetOrdinal("Zeilenversion")),
							Anzahl		= Convert.ToInt32(_Reader["Anzahl"], CultureInfo.CurrentCulture)
						};
						Add(Listenartikel);
					}	// End While
				}	// End using - Reader
			}	// End Using - SQLCommand
		}	// End fill_Liste
	}	// End class
}	// End namespace
private Nachricht | Beiträge des Benutzers
Jamikus
myCSharp.de - Member



Dabei seit:
Beiträge: 251
Herkunft: Oberhausen (NRW)

beantworten | zitieren | melden

Hallöchen
Zitat von Jessimaus
Beispielsweise bin ich nicht sicher, ob das using nicht besser durch einen try/catch-Block ersetzt werden sollte.

Also einen oder beide using gegen try/catch zu tauschen, wäre hier nicht gegeben. Objekt SQLCommand und SQLReader werden intialisiert und definitiv und sicher dispost, wenn sie nicht mehr gebraucht werden. Eine Verwendung die mehr als erwünscht ist.

Ein Problem, welches mir auffällt ist eher die SQL-Verbindung.
Du prüfst zwar richtig, ob die Verbindung offen ist mittels


 if(_SqlCon.State != ConnectionState.Open)
 {
       _SqlCon.Open();
 }

und öffnest sie notfalls.

1. Wenn du sie öffnest, wieso schließt du sie dann nicht?
2. Der sicherste Weg ist Eine sichere Methode wäre*: Eine Verbindung nur solange offen zu halten, solange sie verwendet wird. Leider ist nicht ganz erkenntlich woher die Verbindung kommt und wie lang ihre Lebensdauer schon besteht.

Vom Stil her würde ich den Select nicht als fest hartverdrahtetes Feld initialisieren.

Beim Konstruktor hätte ich wohl eher eine ArgumentNullException erwartet statt einfach nur ein "return", weil es wohl definitiv ein nicht gewünschtes Ergebnis ist, wenn der Parameter NULL ist.

*Kleine Korrektur nachdem ich mich des Wortes vergriffen habe und mir ein kleines Missgeschick durchgegangen ist.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Jamikus am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16109

beantworten | zitieren | melden

Zitat von Jamikus
Der sicherste Weg ist: Eine Verbindung nur solange offen zu halten, solange sie verwendet wird. Leider ist nicht ganz erkenntlich woher die Verbindung kommt und wie lang ihre Lebensdauer schon besteht.

Der sicherste Weg ist eigentlich ADO.NET das Pooling zu überlassen.
Dafür ist es da.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1892
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

Mein Tipp wäre es erst einmal deinen Code sauber umzusetzen.
Wozu machst du eine Ableitung von Collection, wenn du scheinbar in deinem Code nichts davon implementierst.
Ebenfalls solltest du deinen Datenmodel Code von der Datenschicht trennen.
Hier solltest du dringend das Drei Schichten Modell umsetzen.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
pinki
myCSharp.de - Member

Avatar #avatar-4072.jpg


Dabei seit:
Beiträge: 703
Herkunft: OWL

beantworten | zitieren | melden

Zitat von T-Virus
Wozu machst du eine Ableitung von Collection, wenn du scheinbar in deinem Code nichts davon implementierst.

Ganz unten wird die Add- und ziemlich mittig die Clear-Methode verwendet.
private Nachricht | Beiträge des Benutzers
Jessimaus
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Hallo Jamikus,

vielen Dank für Deine Hinweise.

Die SQL-Verbindung ist Bestandteil von MdbCon und die ist in der Regel geschlossen.
Die Prüfung auf NULL im Konstruktor könnte man in der Tat weglassen, weil, wenn dieses Teil NULL ist, dann stirbt die ganze Anwendung ab.
Ich hatte mal die 30-Tage Testversion vom Resharper drauf und der hat rumgemeckert von wegen 'possible System.NullReferenzExceprion'.

Geschlossen wird die SQL-Verbindung automatisch zusammen mit dem Reader, wegen CommandBehavior.CloseConnection.

Wegen der using mache ich mir Gedanken, was passiert, wenn innerhalb dieser Blöcke irgendwas schiefgeht. Dann fliegt mir bzw. dem
Benutzer eine unbehandelte Ausnahme um die Ohren. Vielleicht sollte man innerhalb der using-Blöcke ein try/catch einbauen? Oder außen herum?

@T-Virus
Ich brauche eine Liste/Collection vom Typ Artikelstamm, warum soll ich also nicht von Collection ableiten?

Mit

var Artikelliste = new LstArtikelstamm(MdbCon);
baue ich mir die Liste, die ich ans DataGrid oder die Combobox binde. Einfacher geht's doch gar nicht, oder? Leite ich nicht von Collection ab,
sondern erstelle die Liste innerhalb einer einfachen Klasse, habe ich doch auch nichts anderes als die Liste aller Artikel.

Gruß Jessimaus
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1053

beantworten | zitieren | melden

Zitat von Jessimaus
Vielleicht sollte man innerhalb der using-Blöcke ein try/catch einbauen? Oder außen herum?

using und try/catch schließen sich nicht gegenseitig aus und haben auch per se überhaupt nichts miteinander gleich. Das eine kümmert sich um das Aufräumen von Ressourcen, das andere um die Fehlerbehandlung.
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1892
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@pinki
Hatte ich leider übersehen, aber das Konzept ist aus meiner Sicht nicht sinnvoll.
Ableiten sollte man nur, wenn man die Methode überschrieben will.
In diesem Kontext würde ich das ganze Model und die Datenschicht trennen.
Solchen Code würde ich nie schreiben, da hier keine saubere Schichten Trennung herrscht und der Code jetzt schon ziemlich unleserlich ist.

@Jessimaus
Hier wäre es sinnvoll das Drei Schichten Modell zu fahren.
Dann brauchst du auch keine Ableitung von Collection, was ohne Neuimplemntierung der Methoden nicht zielführend ist.

Hier wäre es sinnvoller das Drei Schichten Modell umzusetzen.
Dann hast du deine Definitionsschicht in dem deine Klasse Artikelstamm ohne Methoden sondern rein aus Properties und Konstruktor besteht.

Darüber liegt dann die Datenschicht, in der deine Lese-/Schreibvorgänge gegen die DB liegen.
Hier hättest du dann z.B. eine ListArtikelstamm Methode, die dir einfach eine List<Artikelstamm> Liste gibt.

Über der Datenschicht liegt dann die Anwendungsschicht, die sowohl Business Logik als auch den Zugriff zur Datenschicht enthält.

So trennst du sauber deine Verantwortungen von deinen Datenmodell und den Datenspeicherung/-verarbeitung.
Aktuell wirfst du dort deinen Code in deine Klasse und gibst ihr dann auch noch Abhängigkeiten für die Datenbank.
Ebenfalls missbrauchst du eine Ableitung unnötig um eine Liste von Artikelstamm zu bekommen.
Solchen Code solltest du dringend überarbeiten.
Ich vermute mal, dass deine Artikelstamm Klasse sich dann auch um das Anlegen, Ändern, Löschen und auslesen aus der DB kümmert.
Dies würde dann aber auch bedeuten, dass deine gesamte Architektur schon in den Datenmodellen feste verdrahtungen zur DB hat.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4136

beantworten | zitieren | melden

T-Virus: Ich stimme dir hier voll zu!

Und für Jessimaus der passende Artikel dazu: [Artikel] Drei-Schichten-Architektur
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1044
Herkunft: Mainz

beantworten | zitieren | melden

Hi,

wenn es hier schon um Daten geht - möchte ich an dieser Stelle neben der bereits erwähnten 3-Schicht-Architektur noch auf folgende Patterns hinweisen:
a) UnitOfWorkPattern
b) RepositoryPattern

Speziell letztere sieht in deinem Fall sehr interessant aus.

Des Weiteren wären Bibliotheken wie z.B. "Dapper" noch sehr interessant um die SQL-Daten zu parsen...

LG
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4136

beantworten | zitieren | melden

Da scheint etwas von der Architektur her generell nicht zu stimmen, denn es gibt ja anscheinend schon einen "Model.POCO" sowie "Model.POCO.Database"-Namensbereich. Ob dann noch mal ein weiterer SQL-Code zum Datenzugriff notwendig ist, bezweifle ich mal...
private Nachricht | Beiträge des Benutzers
Stefan.Haegele
myCSharp.de - Member

Avatar #avatar-3068.jpg


Dabei seit:
Beiträge: 458
Herkunft: Untermeitingen

beantworten | zitieren | melden

Zitat von Jessimaus
private const string COMMANDTEXT = @"SELECT * FROM [dbo].[ilfSelectArtikelliste](@MandantenID)"; [/csharp]

Für viele nur eine Kleinigkeit - für mich im Code immer ein NoGo: SELECT *....
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

Zitat von Stefan.Haegele
Für viele nur eine Kleinigkeit - für mich im Code immer ein NoGo: SELECT *....

SELECT * FROM (SELECT id, name, age FROM people) WHERE rownum ≤100

"Immer" gibt es nicht.

LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
Stefan.Haegele
myCSharp.de - Member

Avatar #avatar-3068.jpg


Dabei seit:
Beiträge: 458
Herkunft: Untermeitingen

beantworten | zitieren | melden

Zitat von LaTino

"Immer" gibt es nicht.

LaTino

Zwar ein wenig aus dem Zusammenhang gerissen, aber ich denke du weisst genau, was ich meinte... :-)
private Nachricht | Beiträge des Benutzers