Laden...

Unabhängigkeit von konkreter (Datenbank-)Klasse

Erstellt von Sclot vor 16 Jahren Letzter Beitrag vor 16 Jahren 2.533 Views
S
Sclot Themenstarter:in
324 Beiträge seit 2007
vor 16 Jahren
Unabhängigkeit von konkreter (Datenbank-)Klasse

Hallo 🙂

Ich bin grad dabei ein kleines Test-Programm zu schreiben um den Umgang mit Datenbanken zu lernen.

Um hier Datenbank-Unabhängig zu sein versuche ich gerade heraus zu finden wie man so etwas anstellen könnte.

Ich gehe hier einfach mal von 3 verschiedenen Verbindungen aus.
Mysql, SQLite und OleDB

Ein einfaches Beispiel zeigt nun das Problem:


MySqlCommand m_cmd = new MySqlCommand();
OleDbCommand o_cmd = new OleDbCommand();
SQLiteCommand s_cmd = new SQLiteCommand();

Nun habe ich ein Command, welches ich wahlweise auswählen kann.
Nur ist es nicht gerade Sinnig eben bei JEDEM Neuen Command auch dieses Spezifische Command zu Instaziieren.

Nun kann man ja Z.B. Toll Klassen ableiten.

Dies könnte ich mir z.B. so vorstellen:


private class SQLCommand : MySqlCommand {}
private class SQLCommand : OleDbCommand {}
private class SQLCommand : SQLiteCommand {}

Dies könnte ich wahlweise irgendwo am Anfang einer Datenbank-Klasse definieren.
Und dann eben statt:

MySqlCommand cmd = new MySqlCommand();

Sowas machen:

SQLcommand cmd = new SQLcommand();

Ja... Schön gedacht... Funktioniert nur nicht 😠
Um zu verstehen warum es dir Typen innerhalb einer Klasse, aber außerhalb einer Methode nicht gibt, reicht mir mein Verständnis noch nicht aus 😠

Letztendlich brauch ich einen Ansatz für eine kleine Universelle Datenbank-Klasse.

R
494 Beiträge seit 2006
vor 16 Jahren

Vielleicht nicht ganz passend zu deiner Frage, aber was du vorhast gibt es schon.
Schau mal nach Klassen wie DbConnection und DbCommand und was sonst noch in deren Namespace so rumlungert.

S
Sclot Themenstarter:in
324 Beiträge seit 2007
vor 16 Jahren

Das sieht in der tat schon recht Interessant aus.
Ich werd damit mal was Versuchen.

Danke auf jeden Fall 🙂

1.433 Beiträge seit 2006
vor 16 Jahren

Du könntest ein Interface erstellen, welches dann an Deine Klasse gebunden ist, dann müsstest Du nur in der jeweiligen Klasse die Datenbank spezifischen Commands und Connections referenzieren.

Dein Interface könnte zum Beispiel so aussehen:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DATA_ACCESS
{
    interface IDBOperations
    {
        void DoOpenDataBase();

        void DoQueryDataBase();

        void DoCloseDataBse();
    }
}

Das wäre dann für die allgemeinen Operationen die Du mit einer DB machen kannst. Danach kannst Du dieses in eine Klasse Deiner Wahl, zum Beispiel DBSql, oder DBOracle oder ähnliches implementieren und dort die jeweiligen DB spezifischen Commands, Connections etc. festlegen.

Beispielklasse DATA welches das Interface implementiert


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace DATA_ACCESS
{
    class DataBase:IDBOperations
    {
        #region IDBOperations Member        

        void IDBOperations.DoOpenDataBase()
        {
            //Hier Dein Code
        }

        void IDBOperations.DoQueryDataBase()
        {
            //Hier Dein Code
        }

        void IDBOperations.DoCloseDataBse()
        {
            //Hier Dein Code
        }

        #endregion
    }
}

Es gibt evenutell noch ausgeklügeltere Varianten, die eventuell von einem erfahreneren Developer als mit gepostet werden könnten. 😭

Grüsse
Daniel
Space Profile
Wer nicht fragt, der nicht gewinnt

915 Beiträge seit 2006
vor 16 Jahren

schaedld hats bereits zwar erklärt allerdings gibt es unter .NET 2 bereits die Schnittstellen dafür.

 System.Data.IDataAdapter;
 System.Data.IDbCommand;
 System.Data.IDbConnection;
 // usw..


Einfach schaedld Beispiel implementieren und die jeweiligen Schnitstellen für die Funktionen als Returns benutzen.

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

S
Sclot Themenstarter:in
324 Beiträge seit 2007
vor 16 Jahren

mhm...

warum kann ich denn nicht einfach sowas machen:


DbCommand sql_cmdd = new DbCommand();

da bekomm ich den Fehler:

Fehler 1 Es konnte keine Instanz der abstrakten Klasse oder Schnittstelle "System.Data.Common.DbCommand" erstellt werden.

J
3.331 Beiträge seit 2006
vor 16 Jahren

warum kann ich denn nicht einfach sowas machen:

Na eben deswegen:

Fehler 1 Es konnte keine Instanz der abstrakten Klasse oder Schnittstelle "System.Data.Common.DbCommand" erstellt werden.

Weil es sich um eine abstrakte Klasse handelt. Aber Du kannst so arbeiten:

//  erzeuge eine spezielle DbProvider-Klasse und daraus eine allgemeine Verbindung
OracleClientFactory newFactory = OracleClientFactory.Instance;
DbConnection connection = newFactory.CreateConnection();
//  alles Weitere geht nur noch mit Db-Klassen
DbCommand cmd = connection.CreateCommand();

Die einzige spezielle Maßnahme ist die Auswahl oder Festlegung einer DbFactory-Instanz. Alles andere läuft mit den allgemeinen Db-Klassen (statt Sql, MySql, OleDb, Fb oder was auch immer; Oracle hier war nur ein Beispiel).

Nachteile: Für DbCommand.Parameters gibt es nur Add, nicht AddWithValue; aber das ist nicht viel mehr als etwas mehr Schreibarbeit. Die unterschiedlichen Dialekte bei den SQL-Befehlen müssen weiterhin beachtet werden. (Zu Lösungen in diesem Zusammenhang wirst Du mit dem Stichwort O/R-Mapper fündig.)

Gruß Jürgen

T
223 Beiträge seit 2006
vor 16 Jahren

Du könntest ein Interface erstellen, welches dann an Deine Klasse gebunden ist, dann müsstest Du nur in der jeweiligen Klasse die Datenbank spezifischen Commands und Connections referenzieren.

Dein Interface könnte zum Beispiel so aussehen:

  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace DATA_ACCESS  
{  
    interface IDBOperations  
    {  
        void DoOpenDataBase();  
  
        void DoQueryDataBase();  
  
        void DoCloseDataBse();  
    }  
}  
  

Das wäre dann für die allgemeinen Operationen die Du mit einer DB machen kannst. Danach kannst Du dieses in eine Klasse Deiner Wahl, zum Beispiel DBSql, oder DBOracle oder ähnliches implementieren und dort die jeweiligen DB spezifischen Commands, Connections etc. festlegen.

Beispielklasse DATA welches das Interface implementiert

  
using System;  
using System.Collections.Generic;  
using System.Data;  
using System.Linq;  
using System.Text;  
  
namespace DATA_ACCESS  
{  
    class DataBase:IDBOperations  
    {  
        #region IDBOperations Member          
  
        void IDBOperations.DoOpenDataBase()  
        {  
            //Hier Dein Code  
        }  
  
        void IDBOperations.DoQueryDataBase()  
        {  
            //Hier Dein Code  
        }  
  
        void IDBOperations.DoCloseDataBse()  
        {  
            //Hier Dein Code  
        }  
  
        #endregion  
    }  
}  
  

Es gibt evenutell noch ausgeklügeltere Varianten, die eventuell von einem erfahreneren Developer als mit gepostet werden könnten. 😭

Hi,

Nichts zum Inhalt, aber das "Do" in den Methodennamen würde ich weglassen, ist falsches Englisch und im Deutschen würdest du doch auch nicht TuÖffneDatenbank schreiben, oder?

Gruß Thomas

1.433 Beiträge seit 2006
vor 16 Jahren

Nichts zum Inhalt, aber das "Do" in den Methodennamen würde ich weglassen, ist falsches Englisch und im Deutschen würdest du doch auch nicht TuÖffneDatenbank schreiben, oder? Nicht wirklich, war ja auch nur auf die Schnelle 😉

Grüsse
Daniel
Space Profile
Wer nicht fragt, der nicht gewinnt

M
110 Beiträge seit 2007
vor 16 Jahren

Schau Dir mal die Beispiele von DbCommand in der MSDN an.

Da ist die Datenbankunabhängigkeit durchdacht worden. Ob es einem gefällt,
wie es gelöst wurde ist eine andere Sache, aber es funktioniert.

Gruss

Mirko

Mappen statt hacken mit Invist , dem .NET O/R Mapper - Code Generator

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Sclot,

Nur ist es nicht gerade Sinnig eben bei JEDEM Neuen Command auch dieses Spezifische Command zu Instaziieren.

nein, sicher nicht. Aber das ist genau die Stunde der Erzeugungs-Entwurfsmuster. Du musst also nichts an deinen Klassen ändern und schon gar nichts selbst ableiten, sondern du musst das richtige Erzeugungs-Entwurfsmuster verwenden. Und das wäre hier wohl abstrakte Fabrik.

herbivore

3.825 Beiträge seit 2006
vor 16 Jahren

Hallo Slot,

bei mir sieht es so aus :

public DbCommand CreateCommand()
{
	DbCommand cmd = null;
	DbProviderFactory factory;
	if (Parameter.dbprovider == Parameter.DatenbankProvider.MicrosoftSQLServer)
	{
		factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
		cmd = factory.CreateCommand();
	}
	if (Parameter.dbprovider == Parameter.DatenbankProvider.SQLServerCompactEdition) cmd = new SqlCeCommand();
	if (Parameter.dbprovider == Parameter.DatenbankProvider.MySQL) cmd = new MySqlCommand();
	if (Parameter.dbprovider == Parameter.DatenbankProvider.OracleSQLServer) cmd = new OracleCommand();
	if (Parameter.dbprovider == Parameter.DatenbankProvider.OleDB) cmd = new OleDbCommand();
	return cmd;
}

Die Sache mit der ProviderFactory funktioniert bei mir leider nur mit SQL-Server, aber so wie oben gehts auch.

Beachte dass die verschiedenen Datenbanken voneinander abweichende Datentypen und abweichende SQL-Syntax haben, siehe http://www.seven-c.de/files/datenbankenhowto.htm#11

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3