Hiermit möchte ich eine kleine Serie beginnen, in welcher ich diverse Features des .Net DataSets (2.0) etwas genauer erläutern möchte.
Es handelt sich dabei hauptsächlich um Features welche ich teilweise selten bis nie verwendet sehe, oder zu welchen es nur sehr magere Informationen gibt!
Heute gehts um Beziehungen im DataSet.
Im Details geht es darum, wie ich in Ausdrücken (Expressions) über eine Beziehung auf andere Tables zugreifen kann.
Konkrete Aufgabenstellung: DataSet mit einer Fakten Tabelle, welche einen Fremdschlüssel enthält. Dieser wiederum verweist auf einen Eintrag in einer Lookup-Tabelle. Ich möchte nun eine beliebige Spalte (NICHT die Schlüsselspalte) aus der Lookuptabelle in meine Fakten-Tabelle einblenden.
Der erste Schritt dorthin kann nur eine berechnte Spalte sein. Jetzt bleibt im Detail nur noch zu klären, wie die Formel der berechnten Spalte aussehen muss damit diese einen Wert aus der Lookuptabelle ergibt.
In reinem SQL würde man sowas mit einem normalen Join oder einer SubQuery lösen, mit dem Nachteil, dass ich nach jeder Änderung (egal ob sich der Fremdschlüssel in der Faktentabelle oder ein Feldinhalt in der Lookuptabelle ändert) das Statement neu ausgeführt werden muss, um einen aktuellen Wert zu sehen. Eine Expression im DataSet kann dies jedoch zur Laufzeit und OHNE Serverzugriff auflösen.
Der dazu passende Beispielcode sieh so aus:
| //Setup Lookup Table DataTable lookuptable = ds.Tables.Add("Lookup"); lookuptable.PrimaryKey = new DataColumn[1] { lookuptable.Columns.Add("Key", typeof(int)) };lookuptable.Columns.Add( "DisplayValue", typeof(string)); lookuptable.Rows.Add(new object[2] { 1, "V1" });lookuptable.Rows.Add( new object[2] { 2, "V2" }); lookuptable.Rows.Add(new object[2] { 3, "V3" });lookuptable.Rows.Add( new object[2] { 4, "V4" }); //Setup Data/Fact Table DataTable facttable = ds.Tables.Add("Facts");facttable.Columns.Add("FactColumn", typeof(string)); //Setup a calculated Column DataColumn ex = facttable.Columns.Add("LookupDisplayValue", typeof(string));DataColumn foreignkeycolumn = facttable.Columns.Add("Lookup_Key", typeof(int)); //Setup Relation between Facts and Lookup DataRelation dr = ds.Relations.Add(lookuptable.PrimaryKey[0], foreignkeycolumn); dr.RelationName = "lookup";ex.Expression = "Parent(lookup).DisplayValue"; ex.ReadOnly = true;facttable.Rows.Add( new Object[3] { "Fact1", System.DBNull.Value, 1 }); facttable.Rows.Add(new Object[3] { "Fact2", System.DBNull.Value, 2 });facttable.Rows.Add( new Object[3] { "Fact3", System.DBNull.Value, 3 }); facttable.Rows.Add(new Object[3] { "Fact4", System.DBNull.Value, 4 }); this.Grid.DataSource = facttable; |
Als erstes werden die Lookup Tabelle definiert und mit Daten gefüllt.
Anschließend werden die Spalten der Fakten-Tabelle definiert, wobei "Lookup_Key" der Fremdschlüssel ist und "LookupDisplayValue" die berechnte Spalte werden soll welche eine beliebige SPalte aus der Lookuptabelle anzeigen kann.
Anschließend wird eine DataRelation definiert und mit dem Namen "lookup" versehen.
Der Punkt, auf den es bei deisem Beispiel ankommt, ist die Berechnungsformel für die Berechnete Spalte
ex.Expression = "Parent(lookup).DisplayValue";
>>Parent<< ist in diesem Fall ein spezielles Schlüsselwort welches die Column anweist einer Relation "zu folgen"
>>(lookup)<< bzeichnet die Beziehung wobei der Name für die Beziehung worher explizit vergeben worden ist
am anderen Ende einer Beziehung kann wiederum nur eine Tabelle stehen und deren Spalten stehen uns jetzt zur AUswahl, hier wird
>>DisplayValue" gewählt.
Natürlich ist jede andere existente Spalte/Formel/Ausdruck usw. auch erlaubt.
Wenn man das Ergebnis von einem Grid anzeigen lässt, kommt man zu folgendem Ergebnis:

Wichtig hier: die Spalte LookupDisplayValue ist Readonly , aber wenn Sie in der Spalte Lookup_Key einen anderen gültigen Lookup-Wert eingeben wird LookupDisplayValue sofort angepasst. Eine andere Spielart der Lookup-Combobox wenn man so will.
Hinweisen möchte ich noch jene Zeilen, welche die Faktentabelle füllen:
facttable.Rows.Add(new Object[3] { "Fact1", System.DBNull.Value, 1 });
Die Berechnte Spalte wird einfach mit DBNull befüllt, etwas anderes würde keinen Sinn machen!
[Edit] An der Darstellung der Quellcodes und der Screenshots arbeite ich noch!
Das compilierfertige Beispiel für VS2005 gibts hier!