Autor Beitrag
Klabautermann
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Veteran
Beiträge: 6366
Erhaltene Danke: 60

Windows 7, Ubuntu
Delphi 7 Prof.
BeitragVerfasst: Mo 12.05.08 20:15 
Hallo,

da ich in Sachen .NET & C# noch recht unbewandert bin habe ich eine ziemlich grundlegende Frage an euch. Ich habe eine Datenbank gebundene Anwendung, welche momentan auf MS-SQL Express entwickelt wird. Zu einem späteren Zeitpunkt möchte ich aber eine Wahlmöglichkeit zwischen verschiedenen Datenbanken implementieren. Ich muss mir also eine anständige Abstraktionsebene für den Datenbankzugriff konzipieren. Ich Delphi würde ich mir eine Klasse von TDataModule ableiten, dieser einige Virtuell-Abstrakte Schnittstellenmethoden verpassen und für jede zu unterstützende Datenbank eine Kindklasse dieser mit ausprogrammierter Schnittstelle implementieren.

Ich nehme an unter C# müsste ich ähnlich vorgehen aber gibt es für meine (WPF) Anwendung ein äquivalent für TDataModule, welches mir erlaubt die Datenbankkomponenten auch Visuell zu manipulieren oder ist es hier das beste eine "normale" Kasse zu nehmen und alles Quelltext gestützt zu machen? Oder gibt es vielleicht eine Tolle neue .NET Technik über die ich da ganz anderes (und natürlich viel Besser) zum Ziel komme?

Gruß
Klabautermann
Robert_G
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 416


Delphi32 (D2005 PE); Chrome/C# (VS2003 E/A, VS2005)
BeitragVerfasst: Di 13.05.08 07:48 
Geht sogar viiiiel besser als mit den komischen DataModules in Delphi.

DataModules zwingen dich dazu globale Variable zu nutzen, wenn du ihren Inhalt im Designer sehen wilst.
Deshalb taugen die Viecher IMHOnicht viel mehr als irgendeine andere TComponent-Ableitung für sowas.

In .Net kannst du einfach eine eigene Komponente anlegen, die dann auch eine Design-surface für non-visuelle Komponenten mitbringt.

Wenn du in dieser Komponente dann IListSource implemtierst, dann kannst du mehrere Datenquelle dem Designer zur Verfügung stellen.
IOW: Du kannst dann deine Komponente irgendwo drauf werfen und die Daten, die sie veröffentlicht an Controls binden, als wäre die Komponente ein DataSet.
boombuler
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 13.05.08 08:44 
Hi,

noch ein kleiner Tipp am Rande: Wenn du im Code nur die Abstrakten Klassen wie System.Data.Common.DbConnection usw. verwendest und dich da wo es möglich ist nur ANSI SQL verwendest hast du so gut wie keinen Portierungsaufwand für verschiedene Systeme. Du musst dann halt nur eine entsprechende Verbindung usw. erstellen und schon funktioniert fast alles von alleine. Es gibt natürlich immer Ausnahmen aber mit dieser Variante unterstützen wir Firebird, MSSQL, Oracle, MySQL und noch ein paar Sachen die wahrscheinlich funktionieren würden, die aber noch nie jemand getestet hat. (Es bietet sich das Factory Pattern an...)

MfG
Florian
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Di 13.05.08 10:18 
Dann will ich mal auch meinen Senf dazu geben...

"Flexible" DB-Zugriffe wurden schon mehrfach entwickelt. Stichwort: O/R-Mapper. Sehr bekannt ist NHibernate. (Ich habe allerdings einen Bogen darum gemacht, weil das noch ein weiteres großes Thema für mich wäre.)

Die Nutzung der abstrakten Klassen von @boombuler ist grundsätzlich sinnvoll. Bedenke aber, dass Du dann die Instanzen anders erzeugen musst:
ausblenden C#-Quelltext
1:
2:
3:
DbProviderFactory dataFactory 
    = DbProviderFactories.GetFactory("FirebirdSql.Data.FirebirdClient");
DbConnection conn = dataFactory.CreateConnection();   // analog auch DbCommand

Problem ist, dass Du dann nur die Standardmöglichkeiten nutzen kannst; AddWithValue geht z.B. nicht:
ausblenden C#-Quelltext
1:
2:
3:
DbCommand cmd = dataFactory.CreateCommand();
cmd.CommandText = "SELECT irgendwas";
cmd.Parameters.AddWithValue("@Value1", value1);


Du musst auch daran denken, dass die verschiedenen DB-Systeme viele Unterschiede aufweisen und dies sich bei der DB-Unabhängigkeit nicht überspielen lässt. Beispiele: Unterschiedliche SELECT-Möglichkeiten, Parameter mit '@' oder ':' oder '?'. Bei NHibernate u.a. wurde versucht, das zu berücksichtigen.

Gruß Jürgen
Robert_G
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 416


Delphi32 (D2005 PE); Chrome/C# (VS2003 E/A, VS2005)
BeitragVerfasst: Di 13.05.08 10:18 
user profile iconboombuler hat folgendes geschrieben:
Hi,

noch ein kleiner Tipp am Rande: Wenn du im Code nur die Abstrakten Klassen wie System.Data.Common.DbConnection usw. verwendest und dich da wo es möglich ist nur ANSI SQL verwendest hast du so gut wie keinen Portierungsaufwand für verschiedene Systeme. Du musst dann halt nur eine entsprechende Verbindung usw. erstellen und schon funktioniert fast alles von alleine. Es gibt natürlich immer Ausnahmen
Ja, ich denke, er wird schon die DbProviderFactories nutzen.
Aber was er da vorhat nennt sich BridgePattern: Auf die Art abstrahiert, kann er auch unterschiedliche SQL Dialekte optimal unterstützen.

Er hat dann wahrscheinlich Methoden wie Gib mir X oder Speciher Y und je nach DBMS wird der SQL Code anders aussehen.

Ich selbst versuche auch möglichst kleine Häppchen zu nehmen, so dass ich bei unterschiedlichen DBMS', nur kleine Portionen anpassen muss.
Zum Beispiel ein Parser für Parameter ist praktisch immer der gleiche, nur der Parameterqualifier ändert sich.
Die Syntax für INSERT INTO...RETURNING... ist in Oracle und Firebird auch fast das gleiche, etc...
Ich habe also verschiedene fertige "Bausteine" aus denen ich mir dann den richtigen DAL für eine bestimmte App zusammenstellen kann, ohne gleich einen Vorschlaghammer wie nHibernate zu bemühen.

Bridges, wie die, die der Klabautermann vorhat, haben auch Vorteile.
Wenn man zum Beispiel relativ wenige getrennte DB-Operationen hat, die aber wiederum sehr von den speziellen Features eines DBMS' profitieren, dann hat man da alles schön unter einem Hut.
Klabautermann Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Veteran
Beiträge: 6366
Erhaltene Danke: 60

Windows 7, Ubuntu
Delphi 7 Prof.
BeitragVerfasst: Di 13.05.08 10:52 
Hi,
user profile iconRobert_G hat folgendes geschrieben:
Geht sogar viiiiel besser als mit den komischen DataModules in Delphi.

das freut mich zu hören.

user profile iconRobert_G hat folgendes geschrieben:
DataModules zwingen dich dazu globale Variable zu nutzen, wenn du ihren Inhalt im Designer sehen wilst.
Deshalb taugen die Viecher IMHOnicht viel mehr als irgendeine andere TComponent-Ableitung für sowas.

Naja, man ist zwar gezwungen die Globale Variable im Quelltext stehen zu haben, aber wenn sie schlichtweg nicht genutzt wird (kein Autocreate für das DM) dürfte sie vom Linker wieder rausgeschmissen werden. Das ist nicht wirklich elegant, hat aber für die Praxis kaum Auswirkungen.

user profile iconRobert_G hat folgendes geschrieben:
In .Net kannst du einfach eine eigene Komponente anlegen, die dann auch eine Design-surface für non-visuelle Komponenten mitbringt.

Wenn du in dieser Komponente dann IListSource implemtierst, dann kannst du mehrere Datenquelle dem Designer zur Verfügung stellen.

Cool, dann werde ich heute Abend mal versuchen das um zu setzen. Es hört sich auf jeden Fall vielversprechend an.

user profile iconRobert_G hat folgendes geschrieben:
IOW: Du kannst dann deine Komponente irgendwo drauf werfen und die Daten, die sie veröffentlicht an Controls binden, als wäre die Komponente ein DataSet.

Hmm, das muss ich wahrscheinlich sehen um es richtig nachvollziehen zu können. Ich nehme an, du sprichst von der abstrakten Schnittstellenkomponente, da müsste ich aber noch im Quelltext festlegen welches Kindobjekt wirklich erzeugt wird oder übersehe ich wieder etwas (was gut möglich ist, da ich noch sehr in Delphi-Denke stecke)?

user profile iconboombuler hat folgendes geschrieben:
noch ein kleiner Tipp am Rande: Wenn du im Code nur die Abstrakten Klassen wie System.Data.Common.DbConnection usw. verwendest und dich da wo es möglich ist nur ANSI SQL verwendest hast du so gut wie keinen Portierungsaufwand für verschiedene Systeme.

Ja, so ist das geplant. Zu 98% werden die einzelnen Schnittstellenimplementierungen einander gleichen. Die größten Unterschiede werden in die Kathegorie Tuning fallen, es gibt Operationen die bei DBMS A performant sind während sie DBMS B ausbremsen. Gelegentlich lohnt es sich auch die Reihenfolge der Bedingungen auf des DBMS anzupassen. Bei Komlexen oder sich häufig wiederholenden Operationen kann sich der Aufwand lohnen. Aber das hat user profile iconRobert_G ja auch gut erklärt.

// Edit: Dieses Post hatte ich ja ganz übersehen:

user profile iconJüTho hat folgendes geschrieben:
"Flexible" DB-Zugriffe wurden schon mehrfach entwickelt. Stichwort: O/R-Mapper. Sehr bekannt ist NHibernate. (Ich habe allerdings einen Bogen darum gemacht, weil das noch ein weiteres großes Thema für mich wäre.)

Ich habe nicht vor da etwas von Drittanbietern zu benutzten. Denn zu viel Flexibilität verlangt meist zu viele Kompromisse. Die Schnittstelle wird sehr "speziell" auf meine Bedürfnisse zugeschnitten sein, also alles andere als Flexibel, lediglich die dahinterliegende Implementierung wird an das DBMS angepasst sein - sofern nötig (die meisten Zugriffe werden in der Art SELECT A, B, C FROM MyTabelle WHERE (ID=XXXX) sein und hier gibt es nicht wirklich viel an das DBMS an zu passen).
Wie also z.B. was an welche DB zu übergeben ist kann ich sehr speziell implementieren wenn ich es für nötig erachte.

Gruß
Klabautermann