Momenteel ben ik bezig met een webapplicatie in .NET waarbij ik een scheiding wil maken tussen Presentatie, Bussines Logic en Data Acces.
Voorals nog concentreer ik me hier op de Data Acces laag. Het is de bedoeling dat gedeelten van de webapplicatie herbruikbaar zijn. Zo wil ik graag dat er een mogelijkheid moet komen om te switchen van database, zonder veel code te moeten wijzigen. Nu heb ik bedacht dat het wellicht handig zou zijn om dat door een aparte class te laten afhandelen. Na veel geinventariseer heb ik besloten om mijn van DAL een Abstract Factory te maken.
Voor testpurposes heb ik het een en ander opgezet en een WinForm (Ik had nog geen locale webserver draaien) gemaakt in Visual Studio .NET 2003, maar het moet ook zo te gebruiken zijn in een webapp neem ik aan. De klassen die je ziet zijn voor het grootste gedeelte kompleet nutteloos, maar daar gaat het even niet om. Het gaat meer om de technieken erachter.
Inmiddels heb ik al (heel) veel informatie over dit onderwerp doorgenomen, over DAL's en Design Patterns e.d.:
[Kleine greep]
Software Design Patterns
J2EE - Data Acces Object
[Alg|.NET] Design van een generiek DbHelper object
[Alg/.NET] Architectuur smart client - Part II concrete case
Design Patterns (het GoF-boek)
[/Kleine greep]
Aangezien ik geen fatsoenlijke tekentools hier heb, geef ik mijn (relevante) stukken source. Omdat ik redelijk nieuw ben in de wereld van .NET heb ik (voor mij) simpel gehouden en zoveel mogelijk van dezelfde namespace in 1 bestand gedrukt. Mijn opzet ziet er zo uit:
DBFactory is een abstracte klasse en wordt geerfd door elke andere database klasse (MSSQL en Oracle hier.). De klasse zelf is een Singleton. Het soort database wat ik werkelijk gebruik, definieer ik in app.config of web.config voor het web. Als je al wilt swappen van database hoef je dat maar op 1 plek te wijzigen. Ook geef ik een geraamte om de juiste type klassen te kunnen gebruiken.
DBFactory.cs
Hier heb ik mijn Sql Server specifieke zaken gezet, deze factory returned de juiste klassen. Voor Oracle heb eenzelfde bestand, alleen returned getVraag een ietwat andere string.
DALSqlServer.cs
Dit zijn de interfaces voor de concrete klassen welke gereturned worden door een van de concrete factory's.
Interfaces.cs
Form1.cs
Alleen nu rijst er bij mij de vraag waar maak ik nou de connectie met de database. Volgens mij moet ik in mijn concrete Vraag en Antwoord klassen lekker SqlCommand en SqlConnection maken etc. Alleen nu sla ik die connection string op in mijn MSSQL factory en kan ik nooit een connectie opbouwen, tenzij ik weer de DBFactory klasse aanroep om alleen de connection string op te halen.
Maw, hoe krijg ik dit fatsoenlijk voor elkaar. Om nou voor elke concrete klasse (zoals Vraag) een aparte constructor op te nemen de connectionstring te initialiseren vind ik ook zo raar. Volgens mij hoort dat helemaal niet zo in een Abstract Factory. Ik maak volgens mij ergens een denkfout, maar waar?
Voorals nog concentreer ik me hier op de Data Acces laag. Het is de bedoeling dat gedeelten van de webapplicatie herbruikbaar zijn. Zo wil ik graag dat er een mogelijkheid moet komen om te switchen van database, zonder veel code te moeten wijzigen. Nu heb ik bedacht dat het wellicht handig zou zijn om dat door een aparte class te laten afhandelen. Na veel geinventariseer heb ik besloten om mijn van DAL een Abstract Factory te maken.
Voor testpurposes heb ik het een en ander opgezet en een WinForm (Ik had nog geen locale webserver draaien) gemaakt in Visual Studio .NET 2003, maar het moet ook zo te gebruiken zijn in een webapp neem ik aan. De klassen die je ziet zijn voor het grootste gedeelte kompleet nutteloos, maar daar gaat het even niet om. Het gaat meer om de technieken erachter.
Inmiddels heb ik al (heel) veel informatie over dit onderwerp doorgenomen, over DAL's en Design Patterns e.d.:
[Kleine greep]
Software Design Patterns
J2EE - Data Acces Object
[Alg|.NET] Design van een generiek DbHelper object
[Alg/.NET] Architectuur smart client - Part II concrete case
Design Patterns (het GoF-boek)
[/Kleine greep]
Aangezien ik geen fatsoenlijke tekentools hier heb, geef ik mijn (relevante) stukken source. Omdat ik redelijk nieuw ben in de wereld van .NET heb ik (voor mij) simpel gehouden en zoveel mogelijk van dezelfde namespace in 1 bestand gedrukt. Mijn opzet ziet er zo uit:
DBFactory is een abstracte klasse en wordt geerfd door elke andere database klasse (MSSQL en Oracle hier.). De klasse zelf is een Singleton. Het soort database wat ik werkelijk gebruik, definieer ik in app.config of web.config voor het web. Als je al wilt swappen van database hoef je dat maar op 1 plek te wijzigen. Ook geef ik een geraamte om de juiste type klassen te kunnen gebruiken.
DBFactory.cs
C#:
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
| using System; using System.Configuration; using TestCompX.Interface; using TestCompX.DALOracle; using TestCompX.DALSqlServer; namespace TestCompX { public abstract class DBFactory { protected static DBFactory _factory; private static string dbtype; private static string connectionString; public static DBFactory getInstance() { dbtype = ConfigurationSettings.AppSettings["DBTYPE"]; connectionString = ConfigurationSettings.AppSettings["DBConnection"]; if (_factory == null) { switch (dbtype) { case "MSSQL" : _factory = new MSSQLFactory(connectionString); break; case "Oracle" : _factory = new OracleFactory(connectionString); break; } } return _factory; } public abstract IVraag getVraag(int i); public abstract IAntwoord getAntwoord(); public abstract IAntwoord getAntwoord(int id); } } |
Hier heb ik mijn Sql Server specifieke zaken gezet, deze factory returned de juiste klassen. Voor Oracle heb eenzelfde bestand, alleen returned getVraag een ietwat andere string.
DALSqlServer.cs
C#:
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
| using System; using TestCompX.Interface; namespace TestCompX.DALSqlServer { public class MSSQLFactory : DBFactory { private string connectionString; public MSSQLFactory() { } public MSSQLFactory(string connectionString) { this.connectionString = connectionString; } // Deze methode wordt vanuit het form uiteindelijk dan aangeroepen. // Maakt een nieuwe vraag met een int en een string. public override IVraag getVraag(int i) { return new Vraag(i, "Dit is een MSSQL Server test"); } public override IAntwoord getAntwoord() { return new Antwoord(); } public override IAntwoord getAntwoord(int id) { return null; } } /* IMPLEMENTATION */ public class Vraag : IVraag { private string vraag; private int id; public Vraag() { this.vraag = ""; this.id = 0; } public Vraag(int id, string vraag) { this.vraag = vraag; this.id = id; } public string getVraag() { return this.vraag; } public int InsertVraag(string vraag) { return 1; } public bool Update(int id) { return true; } public bool Delete(int id) { return false; } public IVraag SearchVraag(int id) { return new Vraag(1, "test"); } public void SelectAllVragen() { } } public class Antwoord : IAntwoord { public Antwoord() { } } } |
Dit zijn de interfaces voor de concrete klassen welke gereturned worden door een van de concrete factory's.
Interfaces.cs
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| namespace TestCompX.Interface { public interface IVraag { int InsertVraag(string vraag); bool Update(int id); bool Delete(int id); IVraag SearchVraag(int id); void SelectAllVragen(); string getVraag(); } public interface IAntwoord { } } |
Form1.cs
C#:
1
2
3
4
5
6
7
8
9
10
11
12
| ... public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); factory = DBFactory.getInstance(); IVraag test = factory.getVraag(1); label1.Text = test.getVraag(); // Ik krijg mooi "Dit is een MSSQL Server test" om mijn scherm } ... |
Alleen nu rijst er bij mij de vraag waar maak ik nou de connectie met de database. Volgens mij moet ik in mijn concrete Vraag en Antwoord klassen lekker SqlCommand en SqlConnection maken etc. Alleen nu sla ik die connection string op in mijn MSSQL factory en kan ik nooit een connectie opbouwen, tenzij ik weer de DBFactory klasse aanroep om alleen de connection string op te halen.
Maw, hoe krijg ik dit fatsoenlijk voor elkaar. Om nou voor elke concrete klasse (zoals Vraag) een aparte constructor op te nemen de connectionstring te initialiseren vind ik ook zo raar. Volgens mij hoort dat helemaal niet zo in een Abstract Factory. Ik maak volgens mij ergens een denkfout, maar waar?