430 likes | 594 Vues
ADO.NET. Ralf Westphal Freier Fachautor & Berater MSDN Regional Director ralfw@ralfw.de. Ausgangsfrage. Wie wollen Sie in OO-Programmen auf Ihre Daten zugreifen? Per relationalem Datenzugriffs-API Cursor, Join etc. Per Objektmodell Objekte, „Collections“, Hierarchien.
E N D
ADO.NET Ralf WestphalFreier Fachautor & BeraterMSDN Regional Director ralfw@ralfw.de
Ausgangsfrage • Wie wollen Sie in OO-Programmen auf Ihre Daten zugreifen? • Per relationalem Datenzugriffs-API • Cursor, Join etc. • Per Objektmodell • Objekte, „Collections“, Hierarchien
Sind Datenbanksysteme nötig? • Kann Datenverwaltung nicht über Objektmodelle stattfinden? • Intuitive Abbildung der „realen Welt“ • Einfache zu Traversieren/Manipulieren • 1 Datenmodell für persistente Daten und in-memory Datenverwaltung, statt 2 • Probleme • Persistenz • Abfragen • Gleichzeitiger Zugriff • Große Datenmengen
Lösungen • Lösungen für mögl. Probleme mit Objektmodellen für die Datenhaltung • Persistenz • Serialisierung (.NET Formatter) • Abfrage • Deklarative Abfragesprache • Meta-Objektmodell • Gleichzeitiger Zugriff • (Objektmodell-)Server • Clients cachen Daten • Große Datenmengen • Server mit beliebiger interner Datendarstellung
Fazit • Datenbanken sind notwendig • Wertvolle Dienstleistungen • Transaktionen, gleichzeitiger Zugriff, Verwaltung großer Datenmengen, Replikation usw. • Objektmodelle stehen nicht im Gegensatz zu Datenbanken • Wir brauchen... • ein vernünftiges Meta-Objektmodell • ein zum Meta-Objektmodell passenden Datenbankzugriffs-APIs
Web/Windows Form Controls VS .NET Designers VS .NET Class Generator Managed Provider myDataSet <xml>…</xml> Data-Adapter DataReader “<xml>…</xml>” Cust Order Item Command Connection XmlReader String Stream XmlText- Reader XmlNode- Reader XmlDocument TextReader ADO.NET Architektur
COM Marshalling Connection oriented OLE DB Provider Zwei mögliche Programmiermod.: ADO OLE DB nativ Cursor Joins für > 1 Tabelle Datentypen von COM/COM+ abhängig COM+, Datasets Disconnected Access Managed Providers Ein Modell: Managed Provider(connected Layer) DataSet (discon.) (Kein Cursor) Kein Join notwendig XML, keine Datentypen Konvertierung nötig ADO vs ADO .NETein Überblick der Änderungen
Data Provider Managed Providers • Interaktion mit Datenquellen „managen“ • Äquivalent des OLE DB Layers • Direkte Darstellung des Consumer Interfaces (nicht mehr mit der Zweiteilung COM/Automation) • Aktuelle Implementierungen • OleDB Managed Provider (ähnlich ADO) • Zugriff auf beliebige OLE DB Provider • SQLServer Managed Provider • Weitere folgen • ODBC • SQL XML Data store
System.Data DataRelation DataSet System.Data.OleDb System.Data.SqlClient DataTable OleDbConnection SqlConnection DataRow OleDbCommand SqlCommand DataColumn OleDbDataReader SqlDataReader OleDbParameter SqlParameter DataSetView OleDbDataAdapter SqlDataAdapter OleDbErrors SqlErrors ... ... Einbindung in die Objekthierarchie ... System.Data System.Data.OleDb System.Data.SqlClient ...
ADO.NET Objekt Model • Das klassische ADO Gewand … • Connection • Command, Parameter • … mit neuen Objekten: • DataReader • Forward-only, Read-only „Recordset“ • DataSet • Disconnected, In-Memory Cache • DataAdapter • Verbindet das DataSet mit der Datenquelle
Connection Objekt • Repräsentation einer Verbindung zu einer Datenquelle • Mit einer Connection ist es möglich … • Die Verbindung zur Datenquelle anzupassen • Transaktionen zu handhaben (Begin, Commit, Abort) • Ähnlichkeiten zum ADODB.Connection Objekt sind nicht unerwünscht
Connection Objekt // Angabe des Namespace (System.Data.SQL) Using System.Data.SqlClient; // Instanziieren eines SQLConnection Objekts SqlConnection cnn = new SqlConnection(); // Connection String setzen cnn.ConnectionString = "server=localhost;uid=sa;database=pubs"; // Öffnen der Connection cnn.Open();
Command Objekt • Stellt ein auszuführendes Kommando dar • Nicht unbedingt ein SQL Kommando • Mit dem ADO .NET Command Objekt ist es möglich: • Ein Statement, welches auf dem Server ausgeführt werden soll, zu definieren • Parameter Informationen für dieses Kommando anzugeben • Rückgabewerte nach der Kommandoausführung zu erhalten • Wie das ADODB.Command Objekt • Kann Parameter enthalten • Werte, die bei Ausführung eines Statements genutzt werden können
// Create Command SqlCommand cmd = new SqlCommand(); // Aktive Connection des Kommandos und Inhalt setzen cmd.ActiveConnection = cnn; cmd.CommandText = "Select au_lname from authors where state = @param1"; // Parameter erzeugen und Werte setzen cmd.Parameters.Add( new SQLParameter("@param1", typeof(String),2) ); cmd.Parameters["@param1"].Value = "CA"; Command Objekt
DataReader • Der DataReader bietet einen forward-only, read-only Datenstrom • Stellt die Ergebnisse einer ausgeführten Abfrage/Kommandos dar • Der DataReader bietet die Möglichkeit … • Einen Ergebnis-Datenstrom von einer Datenquelle zu erhalten • Gleichbedeutend mit einem FO/RO RecordSet • Unterstützt jedoch weder Scrolling noch Updates • Auf Felder greift man am besten mit Hilfe von Accessoren (strongly typed, indexed) zu, die FieldsCollection ist die schlechtere Möglichkeit • Performance • myRow.GetInt(0) • Zugriff über den Feldnamen (einfache Nutzung/Kompatibilität) • myRow["fieldname"] • Unterstützung von DataBinding in WebForms
// DataReader Definieren IDataReader dr; // Kommando ausführen cmd.Execute(out dr); // Ergebnisse auslesen while(dr.Read()) { Console.WriteLine("Name = " + dr["au_lname"]); } // Connection schließen cnn.Close(); DataReader Verwendung
DataSet Tables Table Columns Column Constraints Constraint Rows Row Relations Relation DataSet Common client data store • Relationale Sicht der Daten • Tabellen, Spalten, Zeilen, Beschränkungen, Beziehungen • Direkte Erzeugung von Metadaten einfaches Einfügen von Daten • Explizites Cache Modell • Disconnected, remotable Objekt • Hat keine Kenntnis über die Datenquelle oder deren Eigenschaften • Zugriff wie auf ein Array • Strong Typing möglich
DataSet // Erzeugen eines DataSet "PublicSet" DataSet pubs = new DataSet(" PublicSet"); //Erzeugen einer Tabelle “bestand" DataTable inventory = new DataTable(“bestand"); inventory.Columns.Add(“kennzeichenID",typeof(Int32)); inventory.Columns.Add(“menge",typeof(Int32)); // Tabelle “Bestand” zum DataSet PublicSet hinzufügen pubs.Tables.Add(bestand); // Datensatz zur Bestandstabelle hinzufügen DataRow row = bestand.NewRow(); row[“kennzeichenID"]=1; row[“menge"]=25; bestand.Rows.Add(row);
(Strongly) Typed DataSet • DataSets, Tabellen, Zeilen als Objekte nutzen • Spalten und Beziehungen als Eigenschaften //Ausgabe jedes Autors und dessen Titel foreach (Author myAuthor in Pubs.Authors.Rows) { Console.WriteLine("Name = " + myAuthor.au_lname); foreach (Title myTitle in myAuthor.Titles) { Console.WriteLine("Title = " + myAuthor.Title); } }
DataAdapter • Weiß, wie eine Tabelle aus der Datenbank geladen wird und schreibt Änderungen zurück • Fill(DataSet) • Update(DataSet) • Mapping zwischen Tabellen und Spalten • Benutzer kann die voreingestellten Kommandos überschreiben (insert/update/delete) • z. B. um Stored Procedures anzugeben • Default-Kommandos mit CommandBuilder erzeugen • Erlaubt es, ein DataSet aus mehreren Datenquellen zu füllen
DataAdapter // Neues DataSetCommand SqlDataAdapter dsAdap = new SqlDataAdapter( "Select * from authors",cnn); // Daten an ein DataSet übergeben dsAdap.Fill(pubs, "Authors"); // Änderungen in den Kundendaten des DataSets durchführen und Update durchführen pubs.Tables["Authors"].Rows[0]["au_lname"]="smith"; SqlCommandBuilder bld = new SqlCommandBuilder(dsAdap); dsAdap.Update(pubs, "Authors");
DataBinding • DataView • Wie ein View auf eine Tabelle • Erlaubt, Sortierreihenfolge und Filter in einem View einer Tabelle festzulegen • Beliebige DataViews können von einer Tabelle erzeugt werden, um unterschiedliche Views der gleichen Tabelle möglich zu machen • Wird für das DataBinding verwendet • DataSetView • Wie ein View, daß auf einem DataSet aufsetzt • Sortierreihenfolge und Filter lassen sich setzen • Erlaubt das Verbinden von DataViews • Wird für das Databinding verwendet
DataBinding • Als Quelle für DataBinding dienen: • (DataReader) • DataTable • DataView • DataSet • DatSetView • Array • Collection • IList • IEnumerable
Zusammenfassung • ADO .NET ist die natürliche Weiterentwicklung von ADO • Bekanntes Connection/Command Modell • Teilung von Persistenz und Programmierung • Optimierter ForwardOnly/ReadOnly Ergebnis-Datenstrom • Expliziter, nicht verbundener relationaler Cache • ADO .NET ist XML optimiert • ADO .NET ist im .NET Framework integriert • Exception Handling, Namensgebung, Notierung • Bessere plattformübergreifende Zusammenarbeit und Sharing der Daten, bessere Skalierbarkeit, strong typing
Überblick • Szenen eines Datenzugriffs • Aufwärmen: • AutoNumber-Felder • Logisches Löschen • Joins & DataSets • Jetzt wird es ernst: • Hierarchische Daten laden • Logisches Sperren • Cool down: • Eigene Datenquellen anbinden
AutoNumber-Felder • AutoNumber-Information wird nicht autom. geladen • Steht erst nach DataAdapter.FillSchema zur Verfügung • DataColumn.AutoIncrementSeed/.AutoIncrementStep müssen gesetzt werden • AutoNumber-Werte in DataTable können nicht in AutoNumber-DB-Felder persistiert werden • Fremdschlüssel geraten aus dem Tritt • Fazit: AutoNumber-Felder vermeiden!
Logisches Löschen • Ein Datensatz wird im DataSet gelöscht, in der Datenbank jedoch nur als gelöscht markiert • Lösung: • Tabelle mit einer Spalte für ein Löschkennzeichen ausstatten • DataAdapter mit speziellem Löschkommando ausstatten • Update mytable set delFlag=@delFlag where pk=@pk
Joins & DataSets • Einsatz bisher • Anbinden von untergeordneten Informationen (Master/Detail) • Anbinden von Lookup-Informationen • Kein (semi)automatischer Update • CommandBuilder generiert keine DML-Anweisungen für DataTables mit mehreren Tabellen • Das ist gut so! • Einsatz mit DataSets • Untergeordnete Informationen über Relationen anbinden • Es müssen mehrere Select-Anweisungen ausgeführt werden • Where-Klauseln untergeordneter Select-Anweisungen müssen Where-Klauseln übergeordneter enthalten • Lookup-Informationen entweder auch über Relationen oder weiterhin über Joins anbinden • Fazit: Joins verlieren mit DataSets an Bedeutung • Joins sind oft keine natürliche Darstellung von Datenbeziehungen
Hierarchische Daten laden • Hierarchische Daten bilden oft eine logische Einheit: „Dokumente“ • DB-APIs kennen keine „Dokumente“ • Daten in „Dokument“-Granularität zu laden, entlastet Netzwerkverbindungen • CRUD-Szenarien profitieren vom Denken in „Dokumenten“ • „Dokumente“ definieren... • Zugriff per „Dokument“-ID (PK des Wurzeldatensatzes) • „Dokumente“ mit eigenem API verwalten...
Hierarchische Daten laden • Mögliche „Dokument“-Definition <table name="customer" basetable="customers" fields="*" pk="custID" checkOutOk="1"> <table name="invoices" basetable="invoices" fields="*" pk="invID" checkOutOk="1"> <table name="lineItems" basetable="invoiceLineItems" fields="*" pk="invLIID"> <lookup basetable="products" fields="description, price" pk="prodID"/> <column name="total" type="System.Double" expression="qty*price"/> </table> <column name="total" type="System.Double„ expression="sum(child(lineItems).total)"/> </table> <table name="comm" basetable="customercommunication" fields="telID, custID, tel" pk="telID"/> </table>
Hierarchische Daten laden • Rudimentärer „Dokument“-API • DataSet CreateDocument() • DataSet GetDocument(string id) • StoreDocument(doc as DataSet) • DeleteDocument(string id) • ToDos • „Dokument“-Definition zuordnen • DB-Anbindung • Validation? • Logisches Sperren?
Logisches Sperren • Sperren von Datensätzen während einer (lange andauernden) Bearbeitung • Probates Mittel: physikalisches Sperren via DB-API • Das ist immer falsch! • ADO.NET bietet dafür keine Mittel • Lösung: Logisches Sperren • Sperrungen werden durch Anwendung verwaltet • Z.B. im Hauptspeicher, spezielle Tabelle
Logisches Sperren • Herausforderungen • Sicherstellen, dass alle Beteiligten die logischen Sperren beachten • Datenzugriff darf nicht mehr direkt stattfinden, sondern nur über einen dedizierten API • Wer (ent)sperrt wann? • Was passiert mit „zu lange“ gesperrten Daten? • Z.B. weil der Client abgestürzt ist • Performantes Sperren vs „dauerhaftes“ Sperren
Eigene Datenquellen anbinden • DataSets werden über Managed Provider gefüllt • DataSets sind unabhängig von Datenquellen • Managed Provider sind nicht auf Datenbanken festgelegt • Managed Provider Klassen • Datenquelle anbinden/manipulieren: Connection, Command • Datenquelle lesen: DataReader, DataAdapter • Datenquelle aktualisieren: DataAdapter • A Simple Managed Provider • Realisierung eines eigenen DataAdapter ist ausreichend • Implementiert IDataAdapter
Fazit • ADO.NET zwingt zum Umdenken • Es gibt (fast) keine Cursor mehr • DataReader ist heute eine „Ausnahme“ • DataSets sind in-memory Datencaches • DataSets unterstützen eine oft natürlichere Sicht auf Daten • ADO.NET bietet kaum „Infrastruktur“ für einige typische Probleme • „Dokument“-Handling • SQL XML .NET Klassen mögen helfen • Logisches Sperren • Die Zukunft? • ResultSets • ObjectSpaces: OR-Mapping
Uff... Fragen!?
ADO .NET Quellen • Jetzt lerne ich ADO.NETRalf Westphal, 400 Seiten, Markt+Technik, 2002 (noch nicht erschienen) • ADO .NET for the ADO Programmerhttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/adonetdev.asp • ADO.NET : Migrating from beta 1 to beta 2http://www.asptoday.com/content/articles/20010802.asp?WROXEMPTOKEN=934243ZaVjEiid0J0l7LCYvBGK • Coping with a New Beta - Connecting to Databaseshttp://www.dotnetjunkies.com/tutorials.aspx?tutorialid=81 • Coping with a New Beta - DataSetCommand to DataAdapterhttp://www.dotnetjunkies.com/tutorials.aspx?tutorialid=83 • Using ADO+ and C# in the .NET Framework - Part 1http://www.asptoday.com/content/articles/20000925.asp?WROXEMPTOKEN=934243ZaVjEiid0J0l7LCYvBGK • Using ADO+ and C# in the .NET Framework - Part 2http://www.asptoday.com/content/articles/20000925.asp?WROXEMPTOKEN=934243ZaVjEiid0J0l7LCYvBGK • Revisiting the Use of ADO in .NET Applicationshttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndive/html/data08092001.asp • Commands in ADO .NEThttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndive/html/data07262001.asp • Data Relations and Relativeshttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndive/html/data07122001.asp • Views and Filtershttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndive/html/data06142001.asp • Paradigmenwechsel mit ADO.NEThttp://www.microsoft.com/germany/ms/msdnbiblio/kolumne/062001rw.htm
Über den Referenten Ralf Westphal ist freier Softwaretechnologievermittler. Er arbeitet als Fachautor, Coach/Berater, Softwareentwickler und Sprecher auf Konferenzen im In- und Ausland wie Microsoft Technical Summit, XML-in-Action, BASTA!, COMDEX, Software Development oder XML One. Der Schwerpunkt seiner Arbeit liegt bei der Vermittlung und Anwendung moderner Softwaretechnologien und -konzepte auf der Microsoft Plattform mit Fokus in den Bereichen OOP/komponentenorientierte Entwicklung, Softwarearchitektur und .NET Framework. Darüber hinaus ist Ralf Westphal einer der deutschen Microsoft MSDN Regional Directors, Mitglied verschiedener Fachbeiräte und war von 1998 bis 2001 Chefredakteur der Visual Basic Fachzeitschrift BasicPro.
Bücher des Referenten .NET kompakt140 Seiten, Spektrum Akademischer Verlag, 2002, ISBN 3827411858 Jetzt lerne ich ADO.NETEinfache Datenbankprogrammierung im .NET- Framework400 Seiten, Markt+Technik, 2002, ISBN 3827262291 (erscheint Mitte 2002)
Empower peoplethrough great softwareany time, any place,and on any device