Share via


Auffüllen eines DataSets mit einem DataAdapter-Objekt

Das ADO.NET-DataSet ist eine speicherresidente Darstellung von Daten, das ein konsistentes relationales und von der Datenquelle unabhängiges Programmiermodell bereitstellt. Das DataSet stellt eine komplette Datengruppe einschließlich Tabellen, Einschränkungen und Beziehungen zwischen Tabellen dar. Da das DataSet von der Datenquelle unabhängig ist, kann ein DataSet sowohl lokale Daten einer Anwendung als auch Daten aus mehreren Datenquellen enthalten. Die Interaktion mit vorhandenen Datenquellen wird über das DataAdapter-Objekt gesteuert.

Jeder in .NET Framework enthaltene .NET Framework-Datenprovider besitzt ein DataAdapter-Objekt: der .NET Framework-Datenprovider für OLE DB besitzt ein OleDbDataAdapter-Objekt, der .NET Framework-Datenprovider für SQL Server ein SqlDataAdapter-Objekt und der .NET Framework-Datenprovider für ODBC ein OdbcDataAdapter-Objekt. Ein DataAdapter-Objekt wird dazu verwendet, Daten aus einer Datenquelle abzurufen und Tabellen in einem DataSet zu füllen. Das DataAdapter-Objekt löst außerdem Änderungen, die am DataSet vorgenommen wurden, in der Datenquelle auf. Das DataAdapter-Objekt verwendet das Connection-Objekt des .NET Framework-Datenproviders, um eine Verbindung zu einer Datenquelle herzustellen. Mit den Command-Objekten werden Daten aus der Datenquelle abgerufen und Änderungen an die Datenquelle zurückgegeben.

Die SelectCommand-Eigenschaft des DataAdapter-Objekts ist ein Command-Objekt, das Daten aus der Datenquelle abruft. Die Eigenschaften InsertCommand, UpdateCommand und DeleteCommand des DataAdapter-Objekts sind Command-Objekte, die Aktualisierungen an den Daten in der Datenquelle entsprechend den Modifikationen an den Daten im DataSet verwalten. Diese Eigenschaften werden im Einzelnen unter Aktualisieren der Datenbank mit einem DataAdapter und dem DataSet.

Mit der Fill-Methode des DataAdapter-Objekts wird ein DataSet mit den Ergebnissen der SelectCommand-Eigenschaft des DataAdapter-Objekts gefüllt. Die Fill-Methode verwendet als Argumente ein zu füllendes DataSet und ein DataTable-Objekt oder den Namen der DataTable, die mit den Zeilen gefüllt werden soll, die von der SelectCommand-Eigenschaft zurückgegeben wurden.

Die Fill-Methode verwendet das DataReader-Objekt implizit, um die Spaltennamen und Spaltentypen zurückzugeben, mit denen die Tabellen im DataSet erstellt werden. Die Daten zum Füllen der Tabellenzeilen im DataSet werden ebenfalls implizit verwendet. Tabellen und Spalten werden nur erstellt, wenn sie noch nicht vorhanden sind. Andernfalls verwendet die Fill-Methode das vorhandene DataSet-Schema. Spaltentypen werden als .NET Framework-Typen entsprechend den Tabellen unter Zuordnen der Datentypen von .NET-Datenprovidern zu .NET Framework-Datentypen erstellt. Primärschlüssel werden nur erstellt, wenn sie in der Datenquelle vorhanden sind und der Wert für DataAdapter.MissingSchemaAction auf MissingSchemaAction.AddWithKey festgelegt ist. Wenn die Fill-Methode ermittelt, dass ein Primärschlüssel für eine Tabelle vorhanden ist, werden Daten im DataSet mit den Daten aus der Datenquelle überschrieben. Dies gilt für Zeilen, deren Werte in der Primärschlüsselspalte mit denen der Zeile übereinstimmen, die von der Datenquelle zurückgegeben wurde. Wurde kein Primärschlüssel gefunden, so werden die Daten an die Tabellen im DataSet angehängt. Die Fill-Methode verwendet beim Füllen des DataSets alle TableMappings, die möglicherweise bestehen (siehe Einrichten von Datentabellen- und Datenspaltenzuordnungen).

Hinweis   Wenn SelectCommand die Ergebnisse eines OUTER JOIN zurückgibt, legt der DataAdapter keinen PrimaryKey-Wert für die sich daraus ergebende DataTable fest. Sie müssen den PrimaryKey selbst definieren, um sicherzustellen, dass doppelte Reihen ordnungsgemäß aufgelöst werden. Weitere Informationen hierzu finden Sie unter Definieren eines Primärschlüssels für eine Tabelle.

Im folgenden Codebeispiel wird eine Instanz eines DataAdapters erstellt, die ein Connection-Objekt zu der Microsoft SQL Server-Datenbank Northwind verwendet und eine DataTable in einem DataSet mit der Kundenliste füllt. Mit der SQL-Anweisung und den Connection-Argumenten, die an den DataAdapter-Konstruktor übergeben werden, wird die SelectCommand-Eigenschaft des DataAdapters erstellt.

SqlClient

Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As SqlCommand = New SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As SqlDataAdapter = New SqlDataAdapter
custDA.SelectCommand = selectCMD

nwindConn.Open()

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

nwindConn.Close()
[C#]
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

SqlCommand selectCMD = new SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

SqlDataAdapter custDA = new SqlDataAdapter();
custDA.SelectCommand = selectCMD;

nwindConn.Open();

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

nwindConn.Close();

OleDb

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" & _
                                                       "Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As OleDbCommand = New OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter
custDA.SelectCommand = selectCMD

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")
[C#]
OleDbConnection nwindConn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" +
                                                "Integrated Security=SSPI;Initial Catalog=northwind");

OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

OleDbDataAdapter custDA = new OleDbDataAdapter();
custDA.SelectCommand = selectCMD;

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

Odbc

Dim nwindConn As OdbcConnection = New OdbcConnection("Driver={SQL Server};Server=localhost;" & _
                                                     "Trusted_Connection=yes;Database=northwind")

Dim selectCMD As OdbcCommand = New OdbcCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As OdbcDataAdapter = New OdbcDataAdapter
custDA.SelectCommand = selectCMD

nwindConn.Open()

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

nwindConn.Close()
[C#]
OdbcConnection nwindConn = new OdbcConnection("Driver={SQL Server};Server=localhost;" +
                                              "Trusted_Connection=yes;Database=northwind");

OdbcCommand selectCMD = new OdbcCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

OdbcDataAdapter custDA = new OdbcDataAdapter();
custDA.SelectCommand = selectCMD;

nwindConn.Open();

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

nwindConn.Close();

Beachten Sie, dass der Code das Connection-Objekt nicht explizit öffnet und schließt. Die Fill-Methode öffnet implizit das Connection-Objekt, das vom DataAdapter verwendet wird, wenn die Verbindung nicht bereits geöffnet ist. Wenn die Fill-Methode die Verbindung geöffnet hat, wird sie auch wieder geschlossen, wenn die Fill-Operation beendet ist. Bei einzelnen Operation, wie Fill oder Update, kann der Code auf diese Weise vereinfacht werden. Wenn Sie jedoch mehrere Operationen durchführen, für die eine geöffnete Verbindung erforderlich ist, können Sie die Leistung der Anwendung verbessern, indem Sie explizit die Open-Methode des Connection-Objekts aufrufen, die Operationen für die Datenquelle durchführen und anschließend die Close-Methode des Connection-Objekts aufrufen. Sie sollten die Verbindung zur Datenquelle so kurz wie möglich geöffnet lassen, um die Ressource freizugeben, damit sie von anderen Clientanwendungen verwendet werden kann.

Mehrere Resultsets

Wenn das DataAdapter-Objekt mehrere Resultsets ermittelt, werden mehrere Tabellen im DataSet erstellt. Diesen Tabellen werden standardmäßig Namen nach dem Schema TabelleN, beginnend mit "Tabelle" für Tabelle0, zugewiesen, die jeweils um eins erhöht werden. Wenn ein Tabellenname als Argument an die Fill-Methode übergeben wird, erhalten die Tabellen standardmäßig Namen nach dem Schema TabellennameN, beginnend mit "Tabellenname" für Tabellenname0, die jeweils um eins erhöht werden.

Füllen eines DataSets mit mehreren DataAdapter-Objekten

Mit einem DataSet können beliebig viele DataAdapter-Objekte verwendet werden. Mit jedem DataAdapter-Objekt können ein oder mehrere DataTable-Objekte gefüllt und Aktualisierungen in die zugehörige Datenquelle übernommen werden. Das DataRelation-Objekt und das Constraint-Objekt können dem DataSet lokal hinzugefügt werden. Dadurch haben Sie die Möglichkeit, Daten aus mehreren unähnlichen Datenquellen zu verbinden. Ein DataSet kann beispielsweise Daten aus einer Microsoft SQL Server-Datenbank, einer über OLE DB bereitgestellten IBM-DB2-Datenbank und einer XML-Datenquelle enthalten. Für die Kommunikation mit den einzelnen Datenquellen sind ein oder mehrere DataAdapter-Objekte zuständig.

Im folgenden Codebeispiel werden eine Kundenliste aus der Northwind-Datenbank unter Microsoft SQL Server 2000 und eine Liste mit Bestellungen aus der Northwind-Datenbank, die unter Microsoft® Access 2000 gespeichert ist, gefüllt. Die gefüllten Tabellen werden mit einem DataRelation-Objekt verbunden, und anschließend werden die Kunden mit ihren jeweiligen Bestellungen angezeigt. Weitere Informationen zu DataRelation-Objekten finden Sie unter Hinzufügen einer Beziehung zwischen Tabellen und Navigieren in einer Beziehung zwischen Tabellen.

Dim custConn As SqlConnection= New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _
                                                 "Initial Catalog=northwind;")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", custConn)

Dim orderConn As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _
                                                       "Data Source=c:\Program Files\Microsoft Office\" & _
                                                       "Office\Samples\northwind.mdb;")
Dim orderDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM Orders", orderConn)

custConn.Open()
orderConn.Open()

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")
orderDA.Fill(custDS, "Orders")

custConn.Close()
orderConn.Close()

Dim custOrderRel As DataRelation = custDS.Relations.Add("CustOrders", _
                                     custDS.Tables("Customers").Columns("CustomerID"), _ 
                                     custDS.Tables("Orders").Columns("CustomerID"))

Dim pRow, cRow As DataRow

For Each pRow In custDS.Tables("Customers").Rows
  Console.WriteLine(pRow("CustomerID").ToString())

  For Each cRow In pRow.GetChildRows(custOrderRel)
    Console.WriteLine(vbTab & cRow("OrderID").ToString())
  Next
Next 
[C#]
SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind;");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", custConn);

OleDbConnection orderConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" +
                                                "Data Source=c:\\Program Files\\Microsoft Office\\Office\\Samples\\northwind.mdb;");
OleDbDataAdapter orderDA = new OleDbDataAdapter("SELECT * FROM Orders", orderConn);

custConn.Open();
orderConn.Open();

DataSet custDS = new DataSet();

custDA.Fill(custDS, "Customers");
orderDA.Fill(custDS, "Orders");

custConn.Close();
orderConn.Close();

DataRelation custOrderRel = custDS.Relations.Add("CustOrders",
                              custDS.Tables["Customers"].Columns["CustomerID"],    
                              custDS.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in custDS.Tables["Customers"].Rows)
{
  Console.WriteLine(pRow["CustomerID"]);
   foreach (DataRow cRow in pRow.GetChildRows(custOrderRel))
    Console.WriteLine("\t" + cRow["OrderID"]);
}

SQL Server-Typ "decimal"

Das DataSet speichert Daten mit Hilfe der .NET Framework-Datentypen. Für die meisten Anwendungen sind sie sehr gut zur Darstellung der Informationen aus der Datenquelle geeignet. Diese Darstellung kann jedoch problematisch werden, wenn es sich bei dem Datentyp in der Datenquelle um den SQL Server-Datentyp decimal handelt. Der .NET Framework-Datentyp decimal lässt maximal 28 signifikante Ziffern zu, während der SQL Server-Datentyp decimal 38 signifikante Ziffern zulässt. Wenn das SqlDataAdapter-Objekt während einer Fill-Operation feststellt, dass die Präzision eines SQL Server-Feldes mit dem Datentyp decimal mehr als 28 Zeichen hat, wird der DataTable die aktuelle Zeile nicht hinzugefügt. Stattdessen tritt das FillError-Ereignis auf, und Sie können überprüfen, ob ein Präzisionsverlust eintritt und entsprechend reagieren. Weitere Informationen zum FillError-Ereignis finden Sie unter Arbeiten mit DataAdapter-Ereignissen. Den SQL Server-Wert decimal erhalten Sie, indem Sie ein SqlDataReader-Objekt verwenden und die GetSqlDecimal-Methode aufrufen.

OLE DB-Kapitel

Hierarchische Rowsets, oder Kapitel (OLE DB-Typ DBTYPE_HCHAPTER, ADO-Typ adChapter), können zum Füllen des DataSet-Inhalts verwendet werden. Wenn das DataAdapter-Objekt während einer Fill-Operation eine in Kapitel unterteilte Spalte ermittelt, wird eine DataTable für die in Kapitel unterteilte Spalte erstellt und diese Tabelle mit den Spalten und Zeilen aus dem Kapitel gefüllt. Als Name der für die in Kapitel unterteilten Spalte erstellten Tabelle wird der Name der übergeordneten Tabelle und der Name der in Kapitel unterteilten Spalte im folgenden Format verwendet: "NameÜbergeordneteTabelleNameInKapitelUnterteilteSpalte". Wenn im DataSet bereits eine Tabelle vorhanden ist, deren Name dem Namen der in Kapitel unterteilten Spalte entspricht, wird die aktuelle Tabelle mit den Kapiteldaten gefüllt. Wenn es in einer vorhandenen Tabelle keine Spalte gibt, die einer Spalte im Kapitel entspricht, wird eine neue Spalte hinzugefügt.

Bevor die Tabellen im DataSet mit den Daten in den in Kapitel unterteilten Spalten gefüllt werden, wird eine Beziehung zwischen der übergeordneten und untergeordneten Tabelle des hierarchischen Rowsets erstellt, indem sowohl der übergeordneten als auch der untergeordneten Tabelle eine Ganzzahlenspalte hinzugefügt wird. Für die übergeordnete Spalte wird die automatische Erhöhung festgelegt, und mit den hinzugefügten Spalten beider Tabellen wird eine DataRelation erstellt. Die hinzugefügte Beziehung wird unter Verwendung des Namens der übergeordneten Tabelle und des Namens der Kapitelspalte folgendermaßen benannt: "NameÜbergeordneteTabelleNameKapitelspalte".

Beachten Sie, dass die entsprechende Spalte nur im DataSet vorhanden ist. Bei Folgefüllungen aus der Datenquelle werden die Änderungen nicht in den vorhandenen Zeilen zusammengeführt, sondern zu den Tabellen neue Zeilen hinzugefügt.

Beachten Sie auch, dass bei Verwendung der DataAdapter.Fill-Überladung mit einer DataTable nur diese Tabelle gefüllt wird. Eine Ganzzahlenspalte mit automatischer Erhöhung wird der Tabelle ebenfalls hinzugefügt, es wird jedoch keine untergeordnete Tabelle erstellt oder gefüllt und keine Beziehung erstellt.

Im folgenden Beispiel wird der MSDataShape-Provider verwendet, um eine Kapitelspalte mit Bestellungen für jeden Kunden in einer Kundenliste zu erstellen. Anschließend wird ein DataSet mit den Daten gefüllt.

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" & _
                                         "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " & _
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " & _
                                      "  RELATE CustomerID TO CustomerID)", nwindConn)

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")
[C#]
OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" +
                                  "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbDataAdapter custDA = new OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " +
                                      "  RELATE CustomerID TO CustomerID)", nwindConn);

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

Wenn die Fill-Operation abgeschlossen ist, enthält das DataSet zwei Tabellen: Customers und CustomersOrders, wobei CustomersOrders der in Kapitel unterteilten Spalte entspricht. Eine weitere Spalte mit dem Namen Orders wird zu der Tabelle Customers hinzugefügt. Zu der Tabelle CustomersOrders wird eine weitere Spalte CustomersOrders hinzugefügt. Für die Spalte Orders in der Tabelle Customers wird die automatische Erhöhung festgelegt. Eine DataRelation, CustomersOrders, wird erstellt. Dazu werden die Spalten verwendet, die den Tabellen hinzugefügt wurden, wobei Customers die übergeordnete Tabelle ist. Die folgenden Tabellen zeigen einige Beispielergebnisse.

Tabellenname: Customers (Kunden)

CustomerID (Kundennr.) CompanyName (Unternehmen) Orders (Bestellungen)
ALFKI Alfreds Futterkiste 0
ANATR Ana Trujillo Emparedados y helados 1

Tabellenname: CustomersOrders (Kundenbestellungen)

CustomerID (Kundennr.) OrderID (Bestellungsnr.) CustomersOrders (Kundenbestellungen)
ALFKI 10643 0
ALFKI 10692 0
ANATR 10308 1
ANATR 10625 1

Siehe auch

Datenzugriff mit .NET Framework-Datenprovidern | Zuordnen der Datentypen von .NET-Datenprovidern zu .NET Framework-Datentypen | DataSet-Klasse | DataTable-Klasse | OleDbCommand-Klasse | OleDbConnection-Klasse | OleDbDataAdapter-Klasse | OdbcCommand-Klasse | OdbcConnection-Klasse | OdbcDataAdapter-Klasse | SqlCommand-Klasse | SqlConnection-Klasse | SqlDataAdapter-Klasse