Datenbankanbindung

Werbung
Kapitel 8: Datenbankanbindung
SoPra 2008 Kap. 8: Datenbankanbindung (1/40)
Übersicht
1. Objekte und relationale Datenbanken
2. SQL
3. ADO.NET
4. Persistenzschicht
SoPra 2008 Kap. 8: Datenbankanbindung (2/40)
Kapitel 8.1: Objekte vs. relationale Datenbanken
Persistente Objekte
• auch ein objektorientiertes Programm muss Daten speichern. . .
• Möglichkeiten
⋆ einfache Dateien: Serialized Objects, XML,. . .
• für große Datenmengen ungeeignet
• keine Sicherheitsmechanismen, . . .
⋆ Persistenz durch Speicherung in DB
• optimiert für große Datenmengen
• bieten Transaktionskonzept
• Backups
• und vieles mehr
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (3/40)
Speichermöglichkeiten
Objektdatenbanken
• unterstützten das OO-Modell direkt
Relationale Datenbanken
• passen nicht direkt zum OO-Modell
• Anpassungen (Zwischenschicht) erforderlich
Sonstige
• hierarchische Datenbanken
• einfache Dateien, XML
• auch hier: Anpassungen erforderlich
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (4/40)
Relationale Datenbanken
Grundlagen
• basiert auf mathematischen Relationen (Tupeln)
• beschreibt Information in Prädikatenlogik und mit Fakten
Entity-Relationship (ER) Modelle
• nur Objekte/Attribute/Relationen
• nur einfache Attribute, keine Listen oder Records
• keine Vererbung/Aggregation etc.
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (5/40)
Abbildung OO nach relational
Impedance Mismatch
• OO und Relationale DB sind stark unterschiedliche Ansätze
OO
Relational
Modellierung
Zustand & Verhalten
nur Daten
Identität
ja
nein
Navigation
über Assoziationen
Daten duplizieren, joins. . .
Anfragen
über Attributwerte
Selektion und Projektion
Granularität
einzelne Objekte
Ergebnismengen
• moderne SW wird meist nach OO-Konzepten entwickelt
• verwendete DBMS sind überwiegend relational
⇒ wichtig: gute Abbildung von OO nach relational
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (6/40)
Grundlagen der Abbildung
Welche Konstrukte müssen wir abbilden?
• Klassen
• Attribute
• Assoziationen
• Vererbungshierarchien
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (7/40)
Beispiel: WebBank
Client
1
Account
Account
1
firstName
lastName
PIN
accountNumber
balance
1
1
IssuingAccount
ReceivingAccount
*
*
Transfer
date
amount
reasonForTransfer
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (8/40)
Object Identifiers
Problem
• Effizienter Tabellenzugriff erfordert eindeutigen Primärschlüssel
• Objekte können nicht anhand ihres Wertes unterschieden werden – sie
besitzen Identität
• Tupel haben keine Identität
Lösung
• Object Identifier (OID)
• Tupeln wird eindeutige OID zugeordnet
• Objekte werden in der DB anhand ihres OIDs identifiziert
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (9/40)
OIDs
No Business Meaning:
• keine Attribute aus dem modellierten Problembereich als OIDs
(d. h. als (Fremd-) Schlüssel)
• bei Attributen oft keine Eindeutigkeit gegeben
• im Prinzip kann sich jedes Attribut ändern, die Objektidentität bleibt aber
unverändert
• Abhängig vom Typ eventuell ineffizient
Wie eindeutig sollen die OIDs sein?
• für die konkrete Klasse?
• innerhalb der Klassenhierarchie?
• über alle Klassen hinweg?
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (10/40)
OIDs - Generierung
Globally/Universally Unique IDs: Berechne quasi eindeutige ID (128 Bit) aus
• MAC-Adresse, Datum, Zeit, oder
• (kryptographischem) Zufallszahlengenerator
• in ASP.NET: Klasse/Struct System.Guid, Methode Guid.NewGuid()
Bewertung
• funktioniert
• Datentabellen nicht gelocked
• proprietär
• zu groß (kein Int/Long mehr)
Es gibt diverse andere Möglichkeiten . . .
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (11/40)
Abbildung von Klassen
Prinzip
Klassen werden auf Tabellen abgebildet.
• die erste Spalte ist für die OID
• dann folgen die Attribute
Client
firstName : String
lastName : String
PIN : int
<<Table>>
Client
OID : uniqueidentifier
firstName : varchar(20)
lastName : varchar(20)
PIN : int
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (12/40)
Abbildung von Attributen
Prinzip
Attribute werden in (≥ 0) Spalten abgebildet.
• einfache Attribute: eine Spalte
• objektwertige Attribute ohne eigene Identität: eine Spalte pro Attribut
Beispiel
Client
firstName : String
lastName : String
PIN : int
address : Address
<<Table>>
Person
Address
street : String
city : String
zip : String
OID : uniqueidentifier
firstName : varchar(20)
lastName : varchar(20)
PIN : int
street : varchar(50)
city : varchar(50)
zip : varchar(5)
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (13/40)
Abbildung von Assoziationen
Prinzip
Jede Assoziation wird auf eine eigene Tabelle abgebildet.
Die OIDs der in Relation stehenden Objekte bilden die Tupel.
Vereinfachung
• 1:1, *:1 Assoziation: keine eigene Tabelle, sondern OID als zusätzliches
Attribut in der anderen Tabelle
• unabhängig von Implementierung der Assoziation
• Portierbarkeit: Keine Mengen von Fremdschlüsseln verwenden
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (14/40)
Abbildung von Klassenhierarchien
• Möglichkeit 1: Eine einzige Tabelle für die gesamte Hierarchie.
⋆ Eine Spalte für jedes Attribut
⋆ NULL für nicht benutzte Attribute
⋆ Eine Spalte für den Typ
• Möglichkeit 2: Eine eigene Tabelle für jede konkrete Klasse mit allen
Attributen (inkl. Attribute aus Superklassen).
• Möglichkeit 3: Eine eigene Tabelle für jede Klasse mit genau den Attributen
der Klasse (ohne Attribute der Superklassen).
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (15/40)
Datenbanktabellen (Zusammenfassung)
Vorgehensweise
• Klassen werden zu Tabellen
• Objekte mit Attributen als Zeilen der Tabellen
• schwache Klassen als zusätzliche Attribute
• OID für jede Klasse/Tabelle
• 1:*-Assoziationen durch Referenz (zusätzliches Attribut) mit Fremdschlüssel
• *:*-Assoziationen durch eigene Tabelle
• Vererbung: drei Möglichkeiten
SoPra 2008 Kap. 8.1: Datenbankanbindung – Objekte vs. relationale Datenbanken (16/40)
Kapitel 8.2: SQL
SQL = Structured Query Language
Anfragen in SQL
• SELECT Selektion von Spalten
• FROM Auswahl beteiligter Tabellen
• WHERE Bedingung für Zeilen
• ORDER BY Sortierung der Zeilen
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (17/40)
Anfragen in SQL (Beispiel WebBank)
Welche Kunden haben die PIN 1234?
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (18/40)
Anfragen in SQL (Beispiel WebBank)
Welche Kunden haben die PIN 1234?
SELECT FirstName, LastName
FROM Client
WHERE PIN = 1234;
Wie heißt der Besitzer des Kontos mit der Nummer 10001?
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (18/40)
Anfragen in SQL (Beispiel WebBank)
Welche Kunden haben die PIN 1234?
SELECT FirstName, LastName
FROM Client
WHERE PIN = 1234;
Wie heißt der Besitzer des Kontos mit der Nummer 10001?
SELECT FirstName, LastName
FROM Client, Account
WHERE
AccountNumber = 10001
and Account = Account.OID
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (18/40)
Anfragen in SQL (JOIN Operator)
Spezialoperator JOIN:
SELECT
FROM
LastName, AccountNumber
Client INNER JOIN Account a
ON (Account = a.OID)
• Liefert alle Paare aus Kunden und Konten
• RIGHT JOIN: liefert zusätzlich alle Paare (NULL, Konto)
für Konten, die keinen Besitzer haben
• Analog LEFT JOIN: Auch Kunden, die kein Konto besitzen
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (19/40)
Anfragen in SQL (Besonderheiten)
Ergebnis hat immer die Form einer Tabelle
Möglichkeiten
• Auswahl von Spalten aus mehreren Tabellen
• Filterung von Zeilen nach relativ komplexen Bedingungen
• Sortierung des Ergebnisses
Einschränkung
• algorithmische Auswertung der Daten nicht möglich
• nur Abfrage positiver Informationen
• eventuell Effizienzprobleme bei komplexen Anfragen
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (20/40)
SQL: Weiteres
Weitere wichtige Befehle:
• create table (neue Tabelle anlegen)
• insert (neue Zeile in eine Tabelle einfügen)
• update (Tabellenzeile ändern)
• delete (Tabellenzeile löschen)
Datentypen:
• int, decimal, datetime
• varchar(max), varbinary(max), xml
• char(n), binary(20)
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (21/40)
SQL: Create table
CREATE TABLE [dbo].[Client](
[OID] [uniqueidentifier] NOT NULL,
[FirstName] [varchar](20) NOT NULL,
[LastName] [varchar](20) NOT NULL,
[PIN] [varchar](50) NOT NULL,
[Account] [uniqueidentifier] NOT NULL
) ON [PRIMARY]
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (22/40)
Mehr Infos
Weitere Informationen z. B.:
• http://msdn.microsoft.com/
• SQL Server 2005 Books online
• Google: ’SQL Tutorial’
• Bibliothek
• Server Explorer in Visual Studio
• Microsoft SQL Server Management Studio Express
Sicherheit:
• SQL-Injection
SoPra 2008 Kap. 8.2: Datenbankanbindung – SQL (23/40)
Kapitel 8.3: ADO.NET
Application Interface (API)
• ADO = ActiveX Data Objects
• Microsoft definiertes generisches Interface, um aus .NET auf Daten
zuzugreifen.
Implementierung (Treiber)
• SQL Server von Microsoft oder Drittanbieter implementiert Interface
• ähnliches Konzept in Java: JDBC
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (24/40)
ADO.NET: Datenbankanbindung 1
SqlConnection erzeugen
using
System.Data.SqlClient;
...
// Verbindungsstring besteht aus Benutzername,
// Passwort, Name des Servers, Name der DB,
// aus Web.config laden
Connection con = new SqlConnection(
ConfigurationManager
.ConnectionStrings["WebBankConnectionString"]
.ConnectionString);
Data Source=”Server”;Initial Catalog=”DB Name”;
User ID=”Login Name”;Password=”XXX”;
”Optionen”
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (25/40)
ADO.NET: Datenbankanbindung 2
Verbindung auf- und abbauen
Connection con = new SqlConnection(...);
// Öffnen der Verbindung
con.Open();
// Hier können Anfragen gestellt werden
...
// Schließen der Verbindung
con.Close();
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (26/40)
ADO.NET (Anfragen 1)
Anfrage stellen
{
string queryString =
"SELECT OID " +
"FROM Account " +
"WHERE accountNumber = 10001;";
SqlCommand cmd = CreateCommand(queryString);
SqlDataReader reader = cmd.ExecuteReader();
cmd.Dispose();
}
catch (SqlException ex) { ... }
try
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (27/40)
ADO.NET (Anfragen 2)
Ergebnis auswerten
try
{
(reader.Read()) {
// Variante 1: Spaltennummer
oid = reader.getString(0);
// Variante 2: Wie Array-Zugriff, mit Cast
oid = (string)reader["OID"];
...
} }
catch (SqlException e) { ... }
while
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (28/40)
ADO.NET (Anfragen 3)
Ergebnis auswerten
try
{
(reader.Read()) {
// Variante 3: Mit Zusatztest, ob
// oid = NULL (falls das erlaubt ist)
if (reader.IsDBNull(0))
oid = "unbekannt";
while
else
oid = (string)(reader.getValue(0));
...
} }
catch (SqlException e) { ... }
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (29/40)
ADO.NET (Update)
Ändern eines Datensatzes
{
string updateString =
"UPDATE [Account] " +
"SET [Balance] = ’" + newBalance + "’, " +
"WHERE OID = ’" + oid + "’;";
SqlCommand cmd = CreateCommand(updateString);
cmd.ExecuteNonQuery();
try
}
catch
(SqlException e) { ... }
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (30/40)
ADO.NET (Update)
Variante ohne Probleme mit Quotes
Problem: spezielle Zeichen (Quotes) in Argumenten – SQL injection!
{ string updateString =
"UPDATE Client " +
"SET FirstName = @fn, LastName = @ln " +
"WHERE OID = @oid";
SqlCommand cmd = CreateCommand(updateString);
cmd.Parameters.Add(new SqlParameter("@fn", newFirstName));
cmd.Parameters.Add(new SqlParameter("@ln", newLastName));
cmd.Parameters.Add(new SqlParameter("@oid", oid));
cmd.ExecuteNonQuery();
} catch (SqlException e) { ... } }
try
SoPra 2008 Kap. 8.3: Datenbankanbindung – ADO.NET (31/40)
Kapitel 8.4: Persistenzschicht
Was wissen wir jetzt?
• Struktur von DB-Tabellen klar
• Manipulation mit SQL-Befehlen
• Aufruf von SQL-Befehlen in C#
• Abbildung von Objektmenge auf DB-Tabellen klar
Persistenzproblem:
1. Daten sollen dauerhaft in DB gespeichert werden.
2. Systemoperationen manipulieren Objekte, keine DB-Tabellen.
Wie also Operationen implementieren?
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (32/40)
Persistenzproblem: Einfache (Nicht-)Lösung 1
Lösung 1: Wir arbeiten nur mit Tabellen, nicht mit Objekten.
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (33/40)
Persistenzproblem: Einfache (Nicht-)Lösung 1
Lösung 1: Wir arbeiten nur mit Tabellen, nicht mit Objekten.
Vorteile:
• Direkte Verwendung der ADO.NET API
• einfach zu programmieren (???)
• am effizientesten (???)
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (33/40)
Persistenzproblem: Einfache (Nicht-)Lösung 1
Lösung 1: Wir arbeiten nur mit Tabellen, nicht mit Objekten.
Vorteile:
• Direkte Verwendung der ADO.NET API
• einfach zu programmieren (???)
• am effizientesten (???)
Nachteile:
• keine Objektorientierung (keine Konzepte aus der Realität, kein
Zusammenhang zum Design)
• damit: Code wird low-level, DB-orientiert
• Ergebnis: Code schlecht wartbar, schlecht zu debuggen
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (33/40)
Persistenzproblem: Einfache Lösung 2
Lösung 2: Zum Programmstart wird die ganze DB hereingeladen und in Objekte
konvertiert. Zum Programmende wird alles hinaus geschrieben.
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (34/40)
Persistenzproblem: Einfache Lösung 2
Lösung 2: Zum Programmstart wird die ganze DB hereingeladen und in Objekte
konvertiert. Zum Programmende wird alles hinaus geschrieben.
Vorteil: Operationen können ganz normal Objekte manipulieren.
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (34/40)
Persistenzproblem: Einfache Lösung 2
Lösung 2: Zum Programmstart wird die ganze DB hereingeladen und in Objekte
konvertiert. Zum Programmende wird alles hinaus geschrieben.
Vorteil: Operationen können ganz normal Objekte manipulieren.
Nachteile:
• Platzbedarf zu groß bei großen Datenmengen
• lange Startup-Dauer
• Datenverlust bei Crash
• keine aktuellen Daten bei mehreren Clients
• Konflikte bei gleichzeitigem Schreiben von mehreren Clients
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (34/40)
Persistenzproblem: Einfache Lösung 3
Lösung 3: Jede Operation liest Objekte aus der DB und schreibt sofort in die
Datenbank, Objekte nur ganz kurzfristig im Speicher.
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (35/40)
Persistenzproblem: Einfache Lösung 3
Lösung 3: Jede Operation liest Objekte aus der DB und schreibt sofort in die
Datenbank, Objekte nur ganz kurzfristig im Speicher.
Vorteil: immer aktuelle Daten, minimaler Hauptspeicherbedarf
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (35/40)
Persistenzproblem: Einfache Lösung 3
Lösung 3: Jede Operation liest Objekte aus der DB und schreibt sofort in die
Datenbank, Objekte nur ganz kurzfristig im Speicher.
Vorteil: immer aktuelle Daten, minimaler Hauptspeicherbedarf
Nachteile:
• alles passiert über ineffiziente DB-Zugriffe
• Datenbank-Code (ADO.NET) überall im Programm
• Was ist mit den Assoziationen eines Objekts?
(sofort mit laden? Deren Assoziationen laden? Eventuell alles laden?)
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (35/40)
Persistenzschicht
Grundidee
• DB-Anschluss (fast) komplett verstecken
⋆ Klassen aus Analyse und Design werden persistent
⋆ Kapseln der SQL-Anfragen in einer Klasse
⋆ Zugriff auf DB (möglichst) nur über Laden und Speichern von Objekten
• Lesen von Assoziationen bei Bedarf
• (fast) so zu benutzen wie ’normale’ Objekte
• zusätzliche Aufgaben:
⋆ Caching (nur dann auf DB zugreifen, wenn notwendig)
⋆ Synchronisation (bei parallelem Zugriff auf DB)
⋆ Transaktionen (mehrere Änderungen passieren nur zusammen)
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (36/40)
Persistenzschicht
Realisierungen
professionelle/generische Lösungen:
• Enterprise Java Beans (EJB)
• Java Persistency API (JPA)
• Hibernate (für Java)
• NHibernate (für C#)
• andere Middleware, z. B. CORBA
• Objektorientierte Datenbanken
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (37/40)
Persistenzschicht
Realisierung
Im SoPra: selbstgemachte Lösung
• zeigt wesentliche Konzepte (⇒ Lerneffekt)
• relativ klein (kein Caching)
• bietet Raum für eigene Verbesserungen
• mehr in Vorlesung Softwaretechnik
• keine Lizenzprobleme . . .
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (38/40)
Persistenzschicht im Sopra
• Kapselung der SQL-Statements in einer Klasse DBConnection
⋆ Generische Methoden zum Lesen/Schreiben/Ändern von Zeilen in einer
Tabelle
⋆ Suchen nach einzelnen Werten (Select)
⋆ Transaktionen
• Eine zentrale Klasse PersistenceManager mit Methoden zum
Lesen/Schreiben/Ändern von persistenten Objekten:
public Object load(String table, Guid oid) { ...}
public void persist(Object o) { ...}
• initiales Anlegen der Tabellen
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (39/40)
Anforderungen an eine persistente Klasse
• Muss ein OID Feld haben (Typ Guid).
• Lade/Speicher/Update-Operation für die Klasse muss in
PersistenceManager programmiert werden.
• Umgang mit Assoziationen: Entscheidung des Programmierers
• Suchen mit Select in einer Tabelle oder gesamte Tabelle als Liste von
Objekten laden und darüber iterieren: Entscheidung des Programmierers
Allgemeine Anforderung: Anwendung kann mit leerer Datenbank starten.
Das heißt: Anwendung hat Code zum Anlegen der Tabellen.
SoPra 2008 Kap. 8.4: Datenbankanbindung – Persistenzschicht (40/40)
Herunterladen