Entwickler-Ecke
C# - Die Sprache - OR-Mapper
maxx - Di 20.04.10 10:04
Titel: OR-Mapper
hallo,
ich habe einen OR-Mapper entworfen. Mich würde interessieren, ob der OK ist. Mir kommt der nämlich unglaublich kompliziert vor. Ich bin sicher, den kann man noch sehr vereinfachen. Ich weiß aber nicht, wie.?.?
Für jede Datenbank-Tabelle gibt es 2 Klassen. Gibt es in der Datenbank eine Tabelle A, gibt es im Programm die Klassen A und DbA. In A stehen die allgemeinen Eigenschaften, in DbA kommen noch Datenbank-spezifische Eigenschaften hinzu (z. B. eine Datenbank-ID).
Bei meinem Testbeispiel nehme ich an, dass ich in der Datenbank 2 Tabellen habe: A und B. A hat einerseits eine 1:n-Beziehung zu B (in C# als BindingList dargestellt), andererseits eine 1:1-Beziehung zu B. Ist zwar ziemlich unsinnig, aber das dient nur dazu, das Programm zu testen.
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: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158:
| using System; using System.ComponentModel; using System.Data; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent();
A a = new A(); a.s = "a1";
DbA dbA = new DbA(); dbA.s = "a1";
B b0 = new B(); b0.s = "b0"; B b1 = new B(); b1.s = "b1"; BindingList<B> cB = new BindingList<B>(); cB.Add(b0); cB.Add(b1); dbA.cB = cB;
B b = new B(); b.s = "b"; dbA.b = b;
foreach (B _b in dbA.cB) MessageBox.Show(_b.s); MessageBox.Show(dbA.b.s);
A _a = (A)dbA; foreach (B _b in _a.cB) MessageBox.Show(_b.s); MessageBox.Show(_a.b.s);
DbA _dbA = new DbA(_a); foreach (DbB _dbB in _dbA.cB) MessageBox.Show(_dbB.s); MessageBox.Show(_dbA.b.s); } } public interface IA { string s { get; set; } IBindingList cB { get; set; } IB b { get; set; } } public class A : IA { public string s { get; set; } public IBindingList cB { get; set; } public IB b { get; set; } public A() { this.cB = new BindingList<B>(); } } public class DbA : A { public int i { get; set; } public DbA() { } public DbA(A a) : this() { this.s = a.s; foreach (IB b in a.cB) this.cB.Add(new DbB(b)); this.b = a.b; } } public interface IB { string s { get; set; } } public class B : IB { public string s { get; set; } public B() { } } public class DbB : B { public int i { get; set; } public DbB() { } public DbB(IB b):this() { this.s=b.s; } } } |
Was mich an dem Programm irgendwie ganz besonders stört ist, dass ich viel mit Interfaces arbeite. Dadurch geht mir die Typsicherheit verloren.
Kha - Di 20.04.10 10:21
maxx hat folgendes geschrieben : |
ich habe einen OR-Mapper entworfen. |
Wohl eher einen
Data Access Layer [
http://en.wikipedia.org/wiki/Data_access_layer] für deine zwei Tabellen ;) . Für einen O/RM müsstest du das auf beliebige Entities und Tabellen verallgemeinern.
maxx hat folgendes geschrieben : |
Was mich an dem Programm irgendwie ganz besonders stört ist, dass ich viel mit Interfaces arbeite. Dadurch geht mir die Typsicherheit verloren. |
Warum trennst du dann überhaupt jede Entity in Interface-Klasse-Klasse :nixweiss: ? Hört sich nach Overengineering an, mach jeweils eine Klasse daraus.
maxx - Di 20.04.10 10:36
Zitat: |
Warum trennst du dann überhaupt jede Entity in Interface-Klasse-Klasse. ? Hört sich nach Overengineering an, mach jeweils eine Klasse daraus. |
Genau das will ich nicht. Es soll eine allgemeine Klasse geben, die universell einsetzbar ist. Diese Klasse soll man dann in unterschiedlichste Formen casten können. Z. B. in eine entsprechende Datenbank-Klasse.
Hier gehts mir auch um eine saubere Trennung. Zuerst überlegt man sich mal, welche Klassen es in einem Programm gibt (in meinem Beispiel die Klassen A und B). Danach kümmert man sich um die Datenbankanbindung und entwirft noch die zugehörigen Klassen DbA und DbB.
Man könnte die Klassen A und B dann auch in beliebige andere Formen casten, sofern man das dann irgendwann mal brauchen sollte. Vielleicht will ich irgendwann mal mit den Klassen A und B ein UFO steuern ;). Dann kann ich mir hierzu noch die Klassen UfoA und UfoB erzeugen und dann - wenn ich das will - z. B. von A nach UfoA casten.
Kha - Di 20.04.10 15:53
Sag ich doch, eindeutig Overengineering :mrgreen: .
Im Ernst, mir ist so etwas noch nicht begegnet und ich sehe bisher auch noch keinen praktischen Nutzen darin.
maxx - Di 20.04.10 20:35
Das ist kein overengineering. Ich kenne einen OR-Mapper, der das auch so trennt. Nämlich "Propel".
Kha - Di 20.04.10 22:04
Meinst du die om/
FooTableMap-Klassen? Das ist doch nur die zwischengespeicherte XML-Datei und leitet vor allem nicht von
FooBase ab.
Ich kenne eigentlich nur die folgenden zwei Ansätze:
- Der User schreibt seine Entity-Klassen als POCOs selbst (alles schön virtual markieren), gefüllt wird dann mithilfe einer externen Config - (N)Hibernate
- Die Entity-Klasse wird aus der Config generiert, der User kann durch Ableiten bzw. im .NET-Fall eher Partial Classes/Methods Logik hinzufügen (Linq2SQL, EF, Propel, ...)
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!