651.book Page 265 Monday, July 22, 2002 12:10 PM Mit relationalen Daten arbeiten 266 Ein kurzer Überblick über relationalen Datenzugriff 270 Mit DataRelation-Objekten im Code arbeiten 288 DataRelation-Objekte in Visual Studio .NET erzeugen 291 DataRelation-Objektreferenz 294 Fragen, die häufiger gestellt werden sollten Datenbanktabellen sind nur selten unabhängige Gebilde. Wenn Sie sich die Tabellen in der Beispiel- datenbank Northwind von Microsoft SQL Server 2000 ansehen, die in der Abbildung 7.1 dargestellt sind, werden Sie bemerken, dass sie alle in Wechselbeziehung miteinander stehen. Beachten Sie, dass keine Tabelle alleine steht. Nicht alle Datenbanken haben einen derart hohen Prozentsatz an verknüpften Tabellen, die meisten aber enthalten Tabellen, die miteinander in Beziehung stehen. Wenn Sie Anwendungen erstellen, werden Sie in Situationen kommen, in denen Sie Daten aus zugehörigen Tabellen in Ihrer Datenbank anzeigen oder programmatisch auf sie zugreifen möchten. Wenn Sie mit Daten aus mehreren DataTable-Objekten arbeiten, benötigen Sie wahrscheinlich vier Arten von Funktionalitäten – für Navigation, Validierung, Aggregation und Kaskadierung. Okay, Kas- kadierung ist eigentlich kein Wort. Aber auch wenn dies ein technisches Buch ist, darf ich trotzdem gelegentlich ein wenig künstlerisch sein. Die Anwender möchten in unterschiedlichen Tabellen navigieren, um in Beziehung stehende Zeilen zu finden, wie z.B. die Bestellungen für einen bestimmten Kunden. Sie möchten ihre Daten überprü- fen, um sicherzustellen, dass sie in der Datenbank keine verwaisten Zeilen erzeugen. Anwendungen machen es häufig erforderlich, dass Sie Aggregatinformationen sammeln – z.B. um die Anzahl der Elemente und die Gesamtkosten einer Bestellung anzuzeigen. Und wenn eine übergeordnete Zeile geändert wird, möchten Sie, dass die Änderungen an die untergeordneten Zeilen weitergegeben wer- den – wenn z.B. eine Bestellung gelöscht wird, möchten Sie wahrscheinlich auch, dass die Artikel, die dieser Bestellung zugeordnet sind, ebenfalls gelöscht werden. In diesem Kapitel werden wir uns ansehen, wie mit dem ADO.NET-DataRelation-Objekt mit Daten von verknüpften DataTable-Objekten gearbeitet wird. Ich werde außerdem ausführlich die Features des ForeignKeyConstraint-Objekts erläutern, die ich im vorigen Kapitel eingeführt habe. 265 651.book Page 266 Monday, July 22, 2002 12:10 PM Abbildung 7.1: Beziehungen zwischen den Tabellen in der Datenbank Northwind Ein kurzer Überblick über relationalen Datenzugriff Offensichtlich hat ADO.NET beim relationalen Datenzugriff keine Pionierarbeit geleistet. Ihm gingen andere Methoden der Verarbeitung von Daten von verknüpften Tabellen voraus. Sehen wir uns die häufigsten Methoden der Arbeit mit Daten von verknüpften Tabellen an und vergleichen sie kurz mit der Verwendung des DataRelation-Objekts. Join-Abfragen Join-Abfragen gehen allen Microsoft-Datenzugriffstechnologien voraus. Sie sind eine einfache Stan- dardmethode, um Daten von mehreren Tabellen in einer einzigen Abfrage abzurufen. Die folgende Abfrage ruft Daten von den Tabellen Customers, Orders und Order Details in der Datenbank Northwind ab: SELECT C.CustomerID, C.CompanyName, C.ContactName, C.Phone, O.OrderID, O.EmployeeID, O.OrderDate, D.ProductID, D.Quantity, D.UnitPrice FROM Customers C, Orders O, [Order Details] D WHERE C.CustomerID = O.CustomerID AND O.OrderID = D.OrderID 266 Kapitel 7 651.book Page 267 Monday, July 22, 2002 12:10 PM Zu den Vorteilen der Join-Abfragen gehören: b Sie sind ein weithin akzeptierter Standard. Jeder Datenbankprogrammierer weiß, wie Join-Abfra- gen verwendet werden. b Sie geben Ergebnisse in einer einzigen Struktur zurück. b Sie lassen sich leicht filtern. Wenn Sie nur die Daten von Kunden aus einem bestimmten Land möchten, können Sie ganz einfach einen Filter zu der Abfrage hinzufügen und die Abfrage gibt nur Daten für diese Kunden zurück. Zu den Nachteilen gehören: b Sie können redundante Daten zurückgeben. Wenn ein Kunde 100 Bestellungen hat, werden für jede einzelne Bestellung die gleichen Kundeninformationen zurückgegeben. (Siehe Abbildung 7.2) Abbildung 7.2: Daten, die von einer Join-Abfrage zurückgegeben werden b Die Aktualisierung ist schwierig. Für ein Datenzugriffsmodell wie ADO.NET ist es schwierig zu wissen, wie die Änderungen an den Ergebnissen einer Join-Abfrage zu interpretieren sind. Wenn Sie z.B. eine Zeile löschen, bedeutet das, dass Sie nur die entsprechende Zeile in der Detail- Tabelle löschen möchten, oder möchten Sie auch die Zeile in den Master-Tabellen löschen? Wenn Sie eine Zeile hinzufügen, möchten Sie dann die Zeile nur zu der Detail-Tabelle hinzufügen, oder möchten Sie auch eine neue Zeile zu den Master-Tabellen hinzufügen? b Die Synchronisierung ist schwierig. Wenn Sie eine übergeordnete Zeile ändern – indem Sie z.B. die Kontaktperson für einen Kunden ändern – müssen Sie die Änderung an die Datenbank über- mitteln und die gesamte Abfrage erneut ausführen, um diese Änderung in allen zugehörigen Zeilen im Resultset zu sehen. Mit relationalen Daten arbeiten 267 651.book Page 268 Monday, July 22, 2002 12:10 PM Separate Abfragen Da Join-Abfragen schon immer dafür bekannt waren, dass sie mit Datenzugriffstechnologien wie DAO und ADO schwer zu aktualisieren waren, haben viele Entwickler separate Abfragen verwendet, um Daten von jeder Tabelle in separate Strukturen abzurufen. Zu den Vorteilen der Verwendung separater Abfragen gehört: b Sie geben insgesamt weniger Daten als Join-Abfragen zurück. b Sie sind für Aktualisierungen besser geeignet. Da Sie eine Struktur wie z.B. ein Recordset ändern, die einer einzelnen Tabelle entspricht, ist es für eine Technologie wie ADO einfach, diese Änderung zu interpretieren und die Daten in Ihrer Datenbank entsprechend zu ändern. b Sie sind besser geeignet für mehrere Datenquellen. Sie können dieses Verfahren verwenden, wenn sich die entsprechenden Tabellen auf unterschiedlichen Datenbanksystemen befinden. Zu den Nachteilen gehört: b Sie erfordern Synchronisierungscode. Um die Bestellung für einen bestimmten Kunden zu fin- den, müssen Sie einen Filter auf das untergeordnete Recordset anwenden und Code schreiben, um die Recordset-Objekte in Übereinstimmung miteinander zu halten. b Sie lassen sich schwierig filtern. Das Konstruieren von Abfragen von Detail-Tabellen, die nur die Zeilen abrufen, die den Zeilen zugehörig sind, die von der Master-Tabelle abgerufen wurden, kann eine Herausforderung sein. Wir werden weiter unten in diesem Kapitel auf dieses Thema eingehen. Hierarchische ADO-Recordset-Objekte ADO 2.0 führte das Konzept eines hierarchischen Recordset ein. Sie können einen speziellen Provi- der und eine spezielle Abfragesyntax verwenden, um die Ergebnisse mehrerer Abfragen in einer einzi- gen Struktur zu kombinieren. Das folgende Codefragment ruft den Inhalt der Tabellen Customers, Orders und Order Detail in ein hierarchisches Recordset ab: Dim rsCustomers As ADODB.Recordset, rsOrders As ADODB.Recorders Dim rsOrderDetails As ADODB.Recordset Dim strConn As String, strSQL As String strConn = "Provider=MSDataShape;Data Provider=SQLOLEDB;" & _ "Data Source=(local)\NetSDK;Initial Catalog=Northwind;" & _ "Trusted_Connection=Yes;" strSQL = "SHAPE {SELECT CustomerID, CompanyName, ContactName, " & _ "ContactTitle FROM Customers} AS Customers APPEND " & _ "((SHAPE {SELECT OrderID, CustomerID, EmployeeID, OrderDate " & _ "FROM Orders} AS Orders APPEND ({SELECT OrderID, ProductID, " & _ "UnitPrice, Quantity FROM [Order Details]} AS OrderDetails " & _ "RELATE 'OrderID' TO 'OrderID') AS OrderDetails) AS Orders " & _ "RELATE 'CustomerID' TO 'CustomerID') AS Orders" Set rsCustomers = New ADODB.Recordset rsCustomers.Open strSQL, strConn, adOpenStatic, adLockBatchOptimistic Set rsOrders = rsCustomers.Fields("Orders").Value Set rsOrderDetails = rsOrders.Fields("OrderDetails").Value Das Recordset verfügt über drei Objektvariablen, aber sie verweisen alle auf Daten, die in einer einzi- gen Struktur verwaltet werden. Wenn Sie durch das Recordset der obersten Ebene navigieren, sind nur die zugehörigen Daten in den Detail-Recordset-Objekten sichtbar. Zu den Vorteilen der Verwendung von hierarchischen Recordset-Objekten gehören: 268 Kapitel 7 651.book Page 269 Monday, July 22, 2002 12:10 PM b Sie geben insgesamt weniger Daten als Join-Abfragen zurück. b Sie geben Daten in einer einzigen Struktur zurück. b Sie erfordern keinen komplexen Synchronisierungscode. b Sie sind für einfache Aktualisierungen geeignet. Hierarchische Recordset-Objekte kommen zwar mit einfachen Aktualisierungen gut zurecht, sie stoßen aber bald an ihre Grenzen. Das Übermit- teln von anstehenden Änderungen an mehrere Tabellen kann im günstigsten Fall problematisch sein. Zu den Nachteilen gehören: b Die Abfragesyntax ist schrecklich. Sehen Sie sich diese Abfrage an! Ich betrachte mich als ADO- Experten, habe mich aber niemals darum gekümmert, die SHAPE-Syntax zu lernen. b Sie bieten wenig Kontrolle. Sie müssen die Beziehung in Ihrer Abfrage definieren. b Sie können nur eine einzige Datenquelle abfragen. b Sie lassen sich schwierig filtern. ADO.NET-DataRelation-Objekte Die ADO.NET-DataRelation unterscheidet sich in der Struktur sehr von hierarchischen Recordset- Objekten. DataRelation-Objekte erfordern keinen zusätzlichen Provider und es ist auch keine scheußliche SHAPE-Abfragesyntax erforderlich. DataRelation-Objekte werden als Teil des Schemas des DataSet-Objekts angesehen. Die DataRelation kombiniert recht einfach die besten Features der separaten Abfrage- und hierar- chischen Recordset-Verfahren zum Verwalten der Daten von verknüpften Tabellen und beseitigt fast alle ihre Nachteile. Die folgende Liste der Vor- und Nachteile soll vorerst Ihren Appetit anregen. Zu den Vorteilen der Verwendung von DataRelation-Objekten gehören: b Sie geben insgesamt weniger Daten zurück als Join-Abfragen. b Sie vereinfachen das Suchen von zugehörigen Daten. b Sie erfordern keinen komplexen Synchronisierungscode. b Sie können erweiterte Aktualisierungsszenarien handhaben. Sie können z.B. neue Kunden vor neuen Bestellungen übermitteln, aber auch bestehende Bestellungen löschen, bevor Sie beste- hende Kunden löschen. Oder Sie können, wenn Sie eine Reihe anstehender Bestellungen und Bestelldetails haben, servergenerierte Autoinkrementwerte für Ihre neuen Bestellungen abrufen, bevor Sie die neuen Bestelldetails übermitteln. Ich werde auf beide Szenarien ausführlich in (cid:1)Kapitel 11 eingehen. b Sie sind dynamisch. Sie können DataRelation-Objekte programmatisch erzeugen, ändern und löschen, bevor oder nachdem Sie die verknüpften Datenbanktabellen abfragen. b Sie unterstützen das Weitergeben von Änderungen. Sie können steuern, ob Änderungen an einer Zeile an untergeordnete Zeilen weitergegeben werden sollen, indem Sie die Eigenschaften der Fremdschlüsseleinschränkung verwenden, die der DataRelation zugeordnet ist. b Sie unterstützen das Erzeugen von Hierarchien von unterschiedlichen Datenquellen. Sie müs- sen die Ergebnisse einer Kundenabfrage in Beziehung zu einer SQL Server-Datenbank setzen und eine Bestellungsabfrage zu einer Oracle-Datenbank? Kein Problem. Zu den Nachteilen gehören: Mit relationalen Daten arbeiten 269 651.book Page 270 Monday, July 22, 2002 12:10 PM b Sie sind schwierig zu filtern. Leider vereinfachen DataRelation-Objekte nicht das Abrufen nur von untergeordneten Zeilen, die den gewünschten übergeordneten Zeilen entsprechen. Ich werde weiter unten in diesem Kapitel auf Möglichkeiten eingehen, solche Szenarien zu behandeln. Mit DataRelation-Objekten im Code arbeiten Sie können mit Ihrem eigenen Code durch mehrere Datentabellen navigieren, Daten überprüfen, zusammensetzen und Änderungen weitergeben, aber Sie können alle diese Funktionen schnell und einfach mit Hilfe des ADO.NET-DataRelation-Objekts ausführen. Sehen wir uns an, wie DataRela- tion-Objekte im Code erzeugt und verwendet werden. DataRelation-Objekte erzeugen Das DataRelation-Objekt verfügt über ein paar wichtige Eigenschaften, die Sie in seinem Konstruk- tor setzen können. Wenn Sie eine DataRelation erzeugen, sollten Sie einen Namen angeben, damit Sie das Objekt in seiner Auflistung finden können. Außerdem sollten Sie die Master- und Detail-Spal- ten angeben, auf denen die Beziehung aufbauen soll. Um das Erstellen zu vereinfachen, verfügt die DataRelation über separate Konstruktoren, die einzelne DataColumn-Objekte und Arrays von DataColumn-Objekten akzeptieren. Das Standardbeispiel für das Erzeugen einer Beziehung verwendet DataTable-Objekte, die Kunden- und Bestellinformationen enthalten, wie jene, die Sie in der Abbildung 7.3 sehen. Mit dem folgenden Codefragment können Sie diese DataRelation erzeugen: Visual Basic .NET 'Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. Dim ds As New DataSet() ... 'Hinzufügen einer DataRelation zwischen den beiden Tabellen. Dim rel As DataRelation rel = New DataRelation("CustomersOrders", _ ds.Tables("Customers").Columns("CustomerID"), _ ds.Tables("Orders").Columns("CustomerID")) ds.Relations.Add(rel) Visual C# .NET //Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. DataSet ds = new DataSet(); ... //Hinzufügen einer DataRelation zwischen den beiden Tabellen. DataRelation rel; rel = new DataRelation("CustomersOrders", ds.Tables["Customers"].Columns["CustomerID"], ds.Tables["Orders"].Columns["CustomerID"]); ds.Relations.Add(rel); 270 Kapitel 7 651.book Page 271 Monday, July 22, 2002 12:10 PM Abbildung 7.3: Zugehörige Informationen anzeigen Wenn Sie eine Beziehung definieren möchten, die auf mehreren Spalten basiert, können Sie einen Konstruktor der DataRelation benutzen, der Arrays von DataColumn-Objekten akzeptiert, wie Sie es in dem folgenden Codefragment sehen: Visual Basic .NET 'Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. Dim ds As New DataSet() ... 'Erzeugen von Arrays, die auf die DataColumn-Objekte verweisen, 'auf denen wir die neue DataRelation aufbauen. Dim colsParent, colsChild As DataColumn() With ds.Tables("ParentTable") colsParent = New DataColumn() {.Columns("ParentColumn1"), _ .Columns("ParentColumn2")} End With With ds.Tables("ChildTable") colsChild = New DataColumn() {.Columns("ChildColumn1"), _ .Columns("ChildColumn2")} End With 'Hinzufügen der neuen DataRelation. Dim rel As DataRelation rel = New DataRelation("MultipleColumns", colsParent, colsChild) ds.Relations.Add(rel) Visual C# .NET //Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. DataSet ds = new DataSet(); ... //Erzeugen von Arrays, die auf die DataColumn-Objekte verweisen, //auf denen wir die neue DataRelation aufbauen. DataTable tblParent, tblChild; DataColumn[] colsParent, colsChild; Mit relationalen Daten arbeiten 271 651.book Page 272 Monday, July 22, 2002 12:10 PM tblParent = ds.Tables["ParentTable"]; colsParent = new DataColumn[] {tblParent.Columns["ParentColumn1"], tblParent.Columns["ParentColumn2"]}; tblChild = ds.Tables["ChildTable"]; colsChild = new DataColumn[] {tblChild.Columns["ChildColumn1"], tblChild.Columns["ChildColumn2"]}; //Hinzufügen der neuen DataRelation. DataRelation rel; rel = new DataRelation("MultipleColumns", colsParent, colsChild); ds.Relations.Add(rel); Die DataRelation verfügt außerdem über ein Paar Konstruktoren, deren Signaturen mit denen über- einstimmen, die wir gerade überprüft haben, die aber auch einen vierten Parameter verwenden, um anzuzeigen, ob Einschränkungen erzeugt werden sollen, damit basierend auf der neuen Beziehung referenzielle Integrität erzwungen wird. Standardmäßig werden mit dem Erzeugen einer neuen Data- Relation Einschränkungen zu Ihren DataTable-Objekten hinzugefügt, falls Einschränkungen nicht bereits existieren. Wir werden in Kürze einen genaueren Blick auf diese Funktionalität werfen. Wenn Sie eine neue DataRelation erzeugt haben, sollten Sie sie an die Relations-Auflistung Ihres DataSet anhängen. Wie beim Erzeugen neuer DataTable- und DataColumn-Objekte können Sie in einem einzigen Aufruf mit Code wie dem folgenden eine neue DataRelation erzeugen und sie an die Relations-Auflistung des DataSet-Objekts anhängen: Visual Basic .NET 'Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. Dim ds As New DataSet() ... 'Hinzufügen einer DataRelation zwischen den beiden Tabellen. ds.Relations.Add("CustomersOrders", _ ds.Tables("Customers").Columns("CustomerID"), _ ds.Tables("Orders").Columns("CustomerID")) Visual C# .NET //Erzeugen eines neuen DataSet und Hinzufügen von DataTable- und DataColumn-Objekten. DataSet ds = new DataSet(); ... //Hinzufügen einer DataRelation zwischen den beiden Tabellen. ds.Relations.Add("CustomersOrders", ds.Tables["Customers"].Columns["CustomerID"], ds.Tables["Orders"].Columns["CustomerID"]); In Beziehung stehende Daten suchen DataRelation-Objekte werden hauptsächlich angewandt, um in Beziehung stehende Daten in ver- schiedenen DataTable-Objekten zu suchen. Das DataRelation-Objekt übernimmt diese Aufgabe aber nicht, zumindest nicht direkt. Diese Funktionalität steht eigentlich über die Methoden Get- ChildRows, GetParentRow und GetParentRows des DataRow-Objekts zur Verfügung. Wie passt die DataRelation in die Gleichung? Wenn Sie irgendeine dieser Methoden auf das DataRow-Objekt 272 Kapitel 7 651.book Page 273 Monday, July 22, 2002 12:10 PM aufrufen, geben Sie eine DataRelation als Parameter der Methode an. Sehen wir uns diese Methoden und ihre Verwendungsweise genauer an. Die Methode GetChildRows des DataRow-Objekts Das Suchen von zugehörigen untergeordneten Zeilen einer Zeile in einer anderen DataTable ist recht einfach. Sie rufen einfach die Methode GetChildRows Ihrer DataRow auf und geben den Namen des DataRelation-Objekts an, das die Beziehung zwischen Ihren DataTable-Objekten defi- niert. Sie können auch das tatsächliche DataRelation-Objekt statt des Objektnamens angeben. Die Methode GetChildRows gibt die zugehörigen Daten als Array von DataRow-Objekten zurück. Das folgende Codefragment ruft die Methode GetChildRows auf und durchläuft die Daten, die sie zurückgibt, in einer Schleife: Visual Basic .NET 'Durchlaufen der Kunden in einer Schleife. Dim rowCustomer, rowOrder As DataRow For Each rowCustomer In ds.Tables("Customers").Rows Console.WriteLine(rowCustomer("CustomerID") & " - " & _ rowCustomer("CompanyName")) 'Durchlaufen der zugehörigen Bestellungen in einer Schleife. For Each rowOrder In rowCustomer.GetChildRows("RelationName") Console.WriteLine(vbTab & rowOrder("OrderID") & " - " & _ rowOrder("OrderDate")) Next rowOrder Next rowCustomer Visual C# .NET //Durchlaufen der Kunden in einer Schleife. foreach (DataRow rowCustomer in ds.Tables["Customers"].Rows) { Console.WriteLine(rowCustomer["CustomerID"] + " - " + rowCustomer["CompanyName"]); //Durchlaufen der zugehörigen Bestellungen in einer Schleife. foreach (DataRow rowOrder in rowCustomer.GetChildRows("RelationName")) Console.WriteLine("\t" + rowOrder["OrderID"] + " - " + rowOrder["OrderDate"]); } Die Methode GetParentRow des DataRow-Objekts Mit DataRelation-Objekten können Sie sich nicht nur durch eine Hierarchie hangeln, sondern auch stromaufwärts schwimmen. Das DataRow-Objekt verwendet eine Methode GetParentRow, die Sie aufrufen können, um die übergeordnete Zeile einer Zeile basierend auf einer DataRelation innerhalb des DataSet zu suchen. Wie die Methode GetChildRows akzeptiert auch GetParentRow ein Data- Relation-Objekt oder eine Zeichenfolge, die den Namen der DataRelation enthält, die Sie benutzen möchten, wie Sie es im folgenden Code sehen: Visual Basic .NET Dim rowCustomer, rowOrder As DataRow 'Durchlaufen der Bestellungen in einer Schleife. For Each rowOrder In ds.Tables("Orders").Rows Console.Write(rowOrder("OrderID") & vbTab & rowOrder("OrderDate")) 'Suchen der zugehörigen Master-Zeile. Mit relationalen Daten arbeiten 273 651.book Page 274 Monday, July 22, 2002 12:10 PM rowCustomer = rowOrder.GetParentRow("CustomersOrders") Console.WriteLine(vbTab & rowCustomer("CompanyName")) Next rowOrder Visual C# .NET DataRow rowCustomer; //Durchlaufen der Bestellungen in einer Schleife. foreach (DataRow rowOrder in ds.Tables["Orders"].Rows) { Console.Write(rowOrder["OrderID"] + "\t" + rowOrder["OrderDate"]); //Suchen der zugehörigen Master-Zeile. rowCustomer = rowOrder.GetParentRow("CustomersOrders"); Console.WriteLine("\t" + rowCustomer["CompanyName"]); } Die Methode GetParentRows des DataRow-Objekts Wenn die Beziehung, mit der Sie arbeiten, eine n:m-Beziehung ist und Sie alle übergeordneten Zeilen nach einer bestimmten DataRow durchsuchen möchten, können Sie die GetParentRows-Methode des DataRow-Objekts verwenden. Die Signaturen für diese Methode sind identisch mit denen der Methode GetChildRows, wie Sie es im folgenden Code sehen: Visual Basic .NET 'Durchlaufen der Kunden in einer Schleife. Dim rowChild, rowParent As DataRow For Each rowChild In ds.Tables("ChildTable").Rows 'Durchlaufen der Master-Zeilen in einer Schleife. Console.WriteLine(rowChild("ChildName")) For Each rowParent In rowChild.GetParentRows("RelationName") Console.WriteLine(vbTab & rowParent("ParentName")) Next rowParent Next rowChild Visual C# .NET //Durchlaufen der Kundenn in einer Schleife. foreach (DataRow rowChild in ds.Tables["ChildTable"].Rows) { Console.WriteLine(rowChild["ChildName"]); //Durchlaufen der Master-Zeilen in einer Schleife. foreach (DataRow rowParent in rowChild.GetChildRows("RelationName")) Console.WriteLine("\t" + rowParent["ParentName"]); } HINWEIS: In einer Datenbank sind, wenn überhaupt, nur wenige Beziehungen n:m-Beziehungen. Weiter unten in diesem Kapitel werden Sie sehen, warum. Die Datenversion für die Ansicht auswählen Stellen Sie sich vor, dass Sie bereits eine Anwendung erstellt haben, mit der Anwender Daten aus Ihrer Datenbank abrufen und diese Daten ändern können. Die Angestellten, die diese Anwendung benutzen, sind aber nicht außerordentlich zuverlässig; sie machen Fehler. Also nutzt die Anwendung 274 Kapitel 7
Description: