Leseprobe (Fallbeispiele)

Werbung
Fallbeispiele
7 Fallbeispiele
275
Fallbeispiele
7 Fallbeispiele
Um einen Überblick über die Notwendigkeit der Erzeugung von XML-Daten aus relationalen Daten und ihre Umwandlung in wiederum relationale Daten zu gewinnen, folgt
ein kurzes Beispiel, das die allgemeine Architektur einer Import-/ Export-Schnittstelle
und eine (De)Serialisierungsschnittstelle auf Basis von T-SQL beschreibt. Solche Import-/Export-Schnittstellen können notwendig sein, weil andere Systeme bestimmte
Datenausschnitte der exportierenden Datenbank benötigen, oder weil die eigene Datenbank als Ziel für solche Daten vorhanden ist. Dies können genauso Buchungs- und
Reservierungssysteme wie Untersuchungs- und Analysesysteme, die auf Basis mehrerer
Datenbanken, die möglicherweise sogar verschiedene Hersteller zum Hintergrund haben, erstellt werden, sein. Techniken der Serialisierung und Deserialisierung können
dann interessant sein, wenn per XML die Serialisierung durchgeführt werden soll und
die Daten nicht in Form einer reinen XML-Datei gespeichert werden soll, sondern stattdessen die Daten relational zerlegt und in einer Datenbank gespeichert werden sollen.
Dies ist auch dann eine interessante Lösung, wenn bspw. eigene, auf XML-basierte
Dateiformate benötigt werden. In diesem Fall würde die Serialisierung sowohl für die
Speicherung im Dateisystem mit einer spektakulären Endung (und natürlich nicht .xml)
als auch für die Speicherung in der Datenbank zum Einsatz kommen.
7.1
De-/Serialisierung von Objekten
Serialisierung bedeutet, dass der Zustand eines Objekts in eine Zeichenkette zerlegt
wird. Dies ist im Normalfall eine in jeder objektorientierten Sprache bereits vorhandene
Möglichkeit. Es entstehen dabei automatisch generierte Zeichenketten, die durchaus
kein XML-Format besitzen (müssen). Im Normalfall kann man allerdings durchaus
diese Zeichenkette lesen und verstehen, da in irgendeiner Art und Weise eine SchlüsselWerte-Liste abgebildet wird und die Namen der Felder/Eigenschaften mit ihren zugehörigen Werten in dieser langen Zeichenkette erscheinen. Um Collections, die wiederum
Objekte enthalten können, oder Arrays ranken sich dann bspw. noch zusätzliche Zeichen wie eckige oder geschweifte Klammern, um die gesamten Daten sowie die einzelnen Einträge zu unterscheiden. Es besteht darüber hinaus auch die Möglichkeit, den
Objektzustand in einer Datenbank zu speichern.
276
Fallbeispiele
7.1.1
XML-Serialisierung als relationale Zerlegung
Neben der automatischen Serialisierung in eine beliebige, jedoch von der Programmiersprache vorgegebene Zeichenkette gibt es auch die Möglichkeit, eine eigene Serialisierung vorzunehmen. Dies ist je nach Programmiersprache einfacher oder schwieriger.
Mit .NET ist es besonders einfach; sofern man dann auch noch die XMLStandardserialisierung verwendet, ist es genauso einfach wie eine Zerlegung in einer
einfachen Programmiersprache wie PHP. Es besteht allerdings immer auch die Möglichkeit, eine eigene Serialisierung zu schreiben, was vom Schwierigkeitsgrad wiederum
ein wenig von der Programmiersprache abhängt. Für die Überlegung dieses Abschnitts
genügt es, dass eine solche Möglichkeit besteht und dass darüber hinaus die Daten in
eine relationale Datenbank und/oder eine Textdatei gespeichert werden sollen.
Durch die Serialisierung ist es möglich, den Objektzustand dauerhaft zu speichern. Dies
erlaubt es, ein Objekt in eben diesem Zustand zu einem späteren Zeitpunkt wieder zu
aktivieren. In Software, die keine Datenbank benötigt, könnte dies bspw. ein Spielzustand (Armeeaufbau, Kampfsituation, erreichte Punktestand, Fähigkeiten) sein. Kommt
eine Datenbank ins Spiel, dann handelt es sich möglicherweise um die Situation, dass
die Daten für die Verwendung durch andere Benutzer (Projektverwaltung) dauerhaft
gespeichert und für relationale Abfragen zur Verfügung stehen wollen. Eine solche
Serialisierung in XML ermöglicht es darüber hinaus auch noch, sehr einfach ein eigenes Dateiformat zu erstellen. Die in XML-serialisierten Objektzustände stellen dann das
Dateiformat dar, welches im Dateisystem gespeichert und nachher wieder durch die
Software eingelesen werden kann.
Die erste Abbildung stellt die Architektur einer solchen Serialisierungsschnittstelle
zunächst grob, die zweite Abbildung dagegen etwas genauer dar. In der ersten Abbildung sieht man unten zunächst die Datenbank, in der Mitte die Schnittstelle, welche in
XML-Format die Daten erwartet, zerlegt und in der Datenbank speichert und dann später in XML zusammensetzt und zurückliefert. In vielfältiger Weise ist dies überhaupt
das Grundprinzip einer über XML realisierten Import-/ Exportschnittstelle, wobei allerdings in diesem besonderen Fall die Datenübertragung für den besonderen Prozess von
Serialisierung und Deserialisierung zum Einsatz kommt. Die Abbildung zeigt dann im
oberen Bereich auf der linken Seite die Software, in der die übermittelten Daten wieder
in Objekte umgewandelt werden oder welche die Objekte serialisiert und speichert. Auf
der rechten Seite der Abbildung ist eine XML-Datei angegeben, die mit einer eigenen
Endung das Dateiformat der Anwendung zeigt. In dieser Datei befindet sich nichts anderes als die XML-Darstellung, welche von der Schnittstelle erzeugt bzw. erwartet wird.
277
Fallbeispiele
Die Schnittstelle selbst sammelt aus verschiedenen Tabellen, in denen die Daten relational zerlegt sind, die benötigten Datensätze und stellt sie in einem selbst definierten
XML-Format zusammen. Hier kann man sich zusätzlich vorstellen, wie Parameter zu
Filterzwecken genutzt werden, um bestimmte Objektzustände nach Parametern auszuwählen. Dies ist dann auch das Format, welches von der Schnittstelle für den Import,
d.h. für den Speichervorgang erwartet wird. In diesem Fall sendet die Software eine
XML-Darstellung an die Schnittstelle, deren Aufgabe darin besteht, diese Darstellung
relational zu zerlegen.
Software
.xml
XMLSchnittstelle
XMLSchnittstelle
Datenbank
Tab 1
Tab 2
Tab 2
Bereich 1
...
Tab 1
Tab 2
Tab 3
...
Bereich 2
Abbildung 4.1: Prinzip der Serialisierung
Die zweite Abbildung greift die erste noch einmal auf, variiert sie allerdings ein wenig,
indem sie etwas mehr Details zeigt. Dieses Mal ist wiederum auf der linken unteren
Seite die Datenbank angezeigt, welche sowohl die Tabellen als auch die Schnittstelle
enthält. Darüber ist die Software angegeben, die nun offensichtlich aus mehreren Objekten besteht. Diese Objekte können einzeln oder zusammengesetzt in der Datenbank
bzw. natürlich auch im Dateisystem gespeichert werden. In diesem Fall muss es einen
278
Fallbeispiele
Serialisierer geben, der in der Lage ist, die verschiedenen Eigenschaftswerte der Objekte in eine XML-Darstellung zu zerlegen und der Schnittstelle zu übergeben. Unten sieht
man wiederum die verschiedenen Tabellen, welche die relationale Darstellung der übermittelten Objektdaten repräsentieren. Sofern es mehrere Schnittstellen gibt, welche
der Reihe nach mit Teil-XML-Darstellungen aufgerufen werden, würde dieser Tabellenverbund dann auch einen sachlogischen Sinnzusammenhang abbilden.
Objekt
Objekt
Objekt
Objekt
Objekt
Objekt
Software
Prozedur
Funktion
Sicht
Prozedur
Funktion
Sicht
Datenbank
Tabelle 1
Tabelle2
Tabelle 3
...
Tabelle 1
Tabelle 2
Tabelle 3
...
Abbildung 4.2: Technik der Serialisierung
Als mögliche Lösungen für die konkrete Implementierung einer solchen Schnittstelle
stehen für den Export Prozeduren, Funktionen und Sichten, für den Import dagegen
hauptsächlich Funktionen und Prozeduren zur Verfügung. Während eine Funktion
rechtsseitig einer Zuweisung aufgerufen werden kann und ihre XML-Daten daher in
Form des Rückgabewerts zurückliefert, wird normalerweise eine Prozedur verwendet,
welche über einen Ausgabeparameter die benötigten Daten der Anwendung zur Verfü-
279
Fallbeispiele
gung stellt. Eine Prozedur ist auch geeignet, XML-Daten entgegenzunehmen und sie
dann passend zu zerlegen. Eine Funktion bietet zwar auch eine analoge Möglichkeit an,
Parameter zu empfangen, sie muss allerdings auch einen Rückgabewert liefern, der
möglicherweise gar nicht benötigt wird. Eine Sicht eignet sich insbesondere für die
Zusammenstellung der Daten im Bereich des Exports.
7.1.2
Beispiele
Die Möglichkeiten von Serialisierung und Deserialisierung sollen aufgrund einer abgewandelten und vereinfachten Product2-Tabelle veranschaulicht werden. Dabei verwendet man auf der einen Seite eine Prozedur, die ein XML-Resultset zurückliefert, und
auf der anderen Seite eine SELECT…FOR XML-Abfrage, welche die XML-Daten direkt
aus der Datenbank abruft. Neben diesen beiden Lösungsansätzen für die Deserialisierung zeigt das Beispiel noch, wie das Zurückschreiben von Datensätzen durch Serialisierung funktioniert, sodass aus einem Objekt in der Software zunächst XML wird,
welches eine Prozedur umwandelt, um das Objekt schließlich wieder in einer relationaler Tabelle zu speichern. Bei der Vorstellung der Deserialisierung zeigt das Beispiel
auch noch, wie man die Standarddeserialisierung und das DOM einsetzen kann, um die
XML-Daten aus der Datenbank abzurufen bzw. im Klienten weiterzuverarbeiten. Eine
letzte Möglichkeit besteht nun noch darin, einen Webdienst zu verwenden. Dieser liefert
dann als Antwort eine XML-Struktur in Form einer SOAP-Nachricht mit dem serialisierten Objekt, während die Anfrage des Klienten den Serialisierungsvorgang abbildet.
Dies entspricht allerdings im Wesentlichen den Techniken, die schon vorgestellt wurden, als die Verwendung von komplexen Nachrichten eingeführt wurde, sodass dies
nicht noch einmal aufgegriffen wird.
7.1.2.1
Vorbereitung im MS SQL Server
Auf dem Server sind einige Vorbereitungen zu treffen, um ein funktionstüchtiges Beispiel erstellen zu können. Zunächst benötigt man eine Datenstruktur, die im einfachsten
Fall aus einer einzigen Tabelle besteht. Es ist auch möglich, eine verschachtelte Struktur
aus einer Eltern-Kind-Tabellenverknüpfung zu erstellen, die dann sowohl in der Software als auch nachher beim Speichervorgang wieder zerlegt wird. Es ließe sich darüber
hinaus auch noch eine XML-Spalte vorstellen, die komplexe Inhalte enthält, welche
man weder in der Daten- noch in der Anwendungsschicht zerlegen möchte. Im aktuellen
Beispiel handelt es sich um eine sehr vereinfachte Darstellung der Product-Tabelle mit
nur fünf Spalten. Diese haben drei verschiedene Datentypen, sodass man sich auf der
Klientenseite dem Problem der Typumwandlung gegenüber sieht.
280
Fallbeispiele
CREATE TABLE Production.Product2 (
ProductID
int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Name
varchar(30) NOT NULL,
ProductNumber nvarchar(25) NOT NULL,
ListPrice
money NOT NULL,
StandardCost
money NOT NULL)
712_01.sql: Tabelle für Beispieldaten
Die Daten stammen direkt aus der gewöhnlichen Product-Tabelle, die man mit Hilfe
einer INSERT…SELECT-Anweisung überträgt.
INSERT INTO Production.Product2
(Name, ProductNumber, ListPrice, StandardCost)
SELECT TOP 5 Name, ProductNumber, ListPrice, StandardCost
FROM Production.Product
WHERE ListPrice > 0
712_01.sql: Übernahme von Daten
Wie oben schon erwähnt, kann man sich verschiedene Objekte denken, die aus einer
relationalen Struktur XML-Daten nach außen liefern. Im Rahmen der Diskussion einer
Import-/Exportschnittstelle, die das Thema des folgenden Abschnitts bildet, kann es hier
Funktionen, Prozeduren und auch XML-Sichten geben. Die verschiedenen Objekte
erfordern zwar unterschiedlichen Quelltext, doch das Grundprinzip ist natürlich dasselbe, sodass es an dieser Stelle genügen soll, nur eine Prozedur zu verwenden. Diese liefert auch die XML-Daten nicht als Parameter zurück, sondern kapselt nur eine Abfrage,
welche XML-Daten zurückliefert.
CREATE PROCEDURE Production.GetProduct(
@vProductNumber nvarchar(25))
AS BEGIN
SELECT * FROM Production.Product2 AS Product
WHERE ProductNumber = @vProductNumber
FOR XML AUTO, ELEMENTS
END
712_01.sql: Prozedur mit XML-Rückgabe
281
Fallbeispiele
Um wiederum XML-Daten entgegen zu nehmen, lassen sich Prozeduren oder Funktionen betrachten. Sichten dürften wohl in diesem Bereich eher selten anzutreffen sein, da
die XML-Daten ja nicht direkt gespeichert werden sollen, sondern erst noch zerlegt
werden müssen. Ob hier dann eine Sicht in Kombination mit einem Trigger, der die
Datenzerlegung durchführt, geeignet ist, ist schlecht vorstellbar, weil eine Reihe von
Funktionen und Prozeduren vielmehr die Möglichkeit bieten, eine Anwendungsschnittstelle anzubieten. Die Prozedur, die im nachfolgenden Quelltext präsentiert wird, erwartet für die Aktualisierung von Produktdaten also nun einen nvarchar(max)-Parameter,
der mit Hilfe von openxml() relational zerlegt und dann für die Aktualisierung verwendet wird. Eine Einfüge-Operation wäre mit diesen relationalen Daten ebenfalls über
Variable oder direkt über eine INSERT…SELECT-Anweisung denkbar.
CREATE PROCEDURE Production.UpdateProduct(
@vProductXML nvarchar(max))
AS BEGIN
-- Variablen
DECLARE @vProductID
int,
@vName
nvarchar(30),
@vProductNumber nvarchar(25),
@vListPrice
money,
@vStandardCost
money,
@idoc int
-- Standardzerlegung und gleichzeitige Eintragung
EXEC sp_xml_preparedocument @idoc OUTPUT, @vProductXML
SELECT @vProductID
@vName
= ProductID,
= Name,
@vProductNumber = ProductNumber,
@vListPrice
= ListPrice,
@vStandardCost
= StandardCost
FROM OPENXML(@idoc, '/Product',2)
WITH (ProductID
Name
int,
varchar(50),
ProductNumber varchar(25),
ListPrice
282
money,
Fallbeispiele
StandardCost
money)
-- Aktualisierung
UPDATE Production.Product2
SET Name = @vName,
ProductNumber = @vProductNumber,
ListPrice = @vListPrice,
StandardCost = @vStandardCost
WHERE ProductID = @vProductID
END
712_01.sql: Prozedur mit XML-Übernahme
7.1.2.2
Verwendung im .NET-Klienten
In der Klientenanwendung benötigt man für die Datenstrukturen, die in der Datenbank
gespeichert werden und in der Anwendung entweder als Transfer- oder sogar als Geschäftsobjekte in Frage kommen, eine objektorientierte Repräsentation. Wie bei verschiedenen Entwurfsmustern für die Datenzugriffsschicht oder das Domänenmodell
kann man hier entweder nur die Felder/Spalten bereitstellen oder auch unmittelbar die
Datenzugriffsmethoden und/oder sogar die Geschäftsmethoden programmieren. Da für
dieses Beispiel keine Geschäftsmethoden notwendig sind und der Datenzugriff über die
Serialisierungs-schnittstelle erfolgt, ist die Klasse Product besonders kurz. Im nachfolgend abgedruckten Quelltext sind darüber hinaus auch noch die öffentlichen Eigenschaften gelöscht. Neben diesen kann man sich also nun noch je nach eingesetzter
Schichtung und Programmiertechniken diverse Methoden sowie wenigstens einen Konstruktor denken, welcher für die Eigenschaften Werte entgegen nimmt, wenn das Objekt
in der Anwendung gefüllt und nicht aus der Datenbank abgerufen wird.
namespace Serialisierung
{
public class Product /* um get/set gekürzt*/
{
private int mProductID;
private string mProductNumber;
public string ProductNumber
private string mName;
283
Fallbeispiele
private double mListPrice;
private double mStandardCost;
}
}
Serialisierung/Product.cs: Gekürzte objektorientierte Tabellenabbildung
In einer Klasse namens ProductSerializer befinden sich nun drei Methoden, von
denen zwei den Datenabruf und die dritte die Datenspeicherung/-aktualisierung durchführen. Dabei zeigt die Methode GetProductStandard(), wie die Standarddeserialisierung genutzt wird, um aus einer XML-Struktur wieder ein Objekt zu erstellen. Dabei
ist die Entsprechung zwischen XML-Struktur und objektorientierter Übersetzung genau
passend, d.h. die Klasse trägt den Namen des XML-Eltern-Elements und die einzelnen
Eigenschaften entsprechen den Kind-Elementen dieses Eltern-Elements.
Zunächst erstellt man eine Datenbankverbindung, deren Verbindungszeichenkette in
einer Eigenschaft der Klasse gespeichert wird. Um das XML aus der DB abzurufen,
erstellt man ein XmlDocument-Objekt. Da die Prozedur GetProduct die XML-Daten
direkt als relationale Ergebnismenge zurückliefert, kann man mit Hilfe eines XmlReader-Objekts die Daten aus der Prozedur abrufen. Dazu setzt man die ExecuteXmlReader()-Methode von SqlCommand ein.
Nachdem man die XML-Nachricht aus der Datenbank eingelesen hat, kann man die
eigentliche Deserialisierung mit Hilfe eines XmlSerializer-Objekts durchführen. Sie
besitzt eine Deserialize()-Methode, die eine so direkte Entsprechung unmittelbar
auflöst.
public Product GetProductStandard(string ProductNumber) {
XmlDocument document = new XmlDocument();
using (SqlConnection connection =
new SqlConnection(ConnectionString)) {
SqlCommand cmd = new SqlCommand("Production.GetProduct",
connection);
cmd.Parameters.Add("@vProductNumber",
SqlDbType.NVarChar);
cmd.Parameters["@vProductNumber"].Value = ProductNumber;
cmd.CommandType = CommandType.StoredProcedure;
connection.Open();
284
Fallbeispiele
XmlReader reader = cmd.ExecuteXmlReader();
document.Load(reader);
connection.Close();
}
XmlSerializer serializer =
new XmlSerializer(typeof(Product));
XmlParserContext context =
new XmlParserContext(null, null, null, XmlSpace.None);
XmlTextReader read = new XmlTextReader(document.OuterXml,
XmlNodeType.Element, context);
Product product = (Product)serializer.Deserialize(read);
return product;
}
Serialisierung/ProductSerializer.cs: Standardserialisierung
Alternativ zu einem DB-Objekt, das XML-Daten zurückliefert, steht es dem Entwickler
natürlich auch frei, mit Hilfe einer FOR XML-Abfrage direkt XML aus der Datenbank
abzurufen. Dies verbirgt zwar nicht die Komplexität der Datenstrukturen, ermöglicht
aber dennoch die Vorteile des XML-Abrufs zu nutzen. Diese liegen insbesondere in der
– wie gerade gesehen – schnellen Erzeugung eines Objekts auch bei vielen Eigenschaften. Die nachfolgende Methode zeigt allerdings neben der direkten Abfrage noch eine
andere Alternative, nämlich die Erzeugung eines Objekts aus dem DOM-Dokument
bzw. aus dem XmlDocument-Objekt mit individuellem Abruf der XML-Elemente.
Man verwendet wie zuvor einen XmlReader, um die XML-Daten aus der Abfrage zu
lesen, und die Load()-Methode von XmlDocument, um die Daten zu übernehmen. Die
SelectSingleNode()-Methode ist dann die einfachste Lösung, um die einzelnen
Knoten in der XML-Struktur auszulesen und die Textknoteninhalte in die Objekteigenschaften zu übernehmen. Bei dieser Variante ist es auf der einen Seite zwar möglich,
individuelle Werte zu übernehmen, doch muss man auf der anderen Seite auch für die
Datentypzuordnung selbst sorgen. Dies zeigen die verschiedenen TryParse()Verwendungen, um die double- und int-Werte aus den XML-Daten umzuwandeln.
public Product GetProductDOM(string ProductNumber) {
XmlDocument document = new XmlDocument();
285
Fallbeispiele
String CommandString = @"SELECT *
FROM Production.Product2 AS Product
WHERE ProductNumber = @vProductNumber
FOR XML AUTO, ELEMENTS";
using (SqlConnection connection =
new SqlConnection(ConnectionString)) {
SqlCommand cmd = new SqlCommand(CommandString,
connection);
cmd.Parameters.Add("@vProductNumber",
SqlDbType.NVarChar);
cmd.Parameters["@vProductNumber"].Value = ProductNumber;
connection.Open();
XmlReader reader = cmd.ExecuteXmlReader();
document.Load(reader);
connection.Close();
}
Product product = new Product();
XmlNode root = document.SelectSingleNode("Product");
product.ProductNumber = root.SelectSingleNode(
"ProductNumber").InnerText;
product.Name = root.SelectSingleNode("Name").InnerText;
bool result;
double wert;
result = double.TryParse(root.SelectSingleNode(
"ListPrice").InnerText.Replace(".", ",") , out wert);
if (result) {
product.ListPrice = wert;
}
result = double.TryParse(root.SelectSingleNode(
"StandardCost").InnerText.Replace(".", ",") , out wert);
if (result) {
product.StandardCost = wert;
}
286
Fallbeispiele
int ID;
result = int.TryParse(root.SelectSingleNode(
"ProductID").InnerText, out ID);
if (result) {
product.ProductID = ID;
}
return product;
}
Serialisierung/ProductSerializer.cs: Eigene DOM-Serialisierung
Schließlich müssen die Daten auch wieder aus der Anwendung in die Datenbank zurückgeschrieben werden. Dazu kann man eine entsprechende Prozedur einsetzen, welche die XML-Daten erwartet, zerlegt und neu speichert oder aktualisiert. Dazu ist es
lediglich wichtig, die Objekteigenschaften in eine XML-Zeichenkette umzuwandeln,
wozu man ein Objekt der Klasse StringWriter verwendet, die bei der Instanziierung
ein Objekt vom Typ StringBuilder erwartet. Die Methode Serialize() der Klasse
XmlSerializer ist dann in der Lage, eine Zeichenkette in XML-Form zu erzeugen,
die unter Verwendung des StringWriter-Objekts eine entsprechende Zeichenkette
erzeugt. Diese Zeichenkette übergibt man dann ganz einfach dem Parameter der entsprechenden DB-Prozedur, die sich um die Datenverarbeitung kümmert.
public void UpdateProduct(Product product) {
XmlSerializer serializer =
new XmlSerializer(typeof(Product));
StringBuilder builder = new StringBuilder();
using (StringWriter writer = new StringWriter(builder)) {
serializer.Serialize(writer, product);
}
String ProductXML = builder.ToString();
using (SqlConnection connection =
new SqlConnection(ConnectionString)) {
SqlCommand cmd =
new SqlCommand("Production.UpdateProduct", connection);
cmd.Parameters.Add("@vProductXML", SqlDbType.NVarChar);
cmd.Parameters["@vProductXML"].Value = ProductXML;
287
Fallbeispiele
cmd.CommandType = CommandType.StoredProcedure;
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
}
}
Serialisierung/ProductSerializer.cs: Eigene DOM-Serialisierung
Auch wenn die vorgestellten Methoden bereits sehr gut geeignet sind, auch die Klientensicht vorstellbar zu machen, folgt nun noch in einer anderen Klasse die Main()Methode, mit der die verschiedenen Methoden getestet werden können. Dabei ruft man
zunächst mit der Standard-Deserialisierung ein gewöhnliches Produkt ab, ändert seine
Eigenschaften und aktualisiert es mit der Serialisierungsmethode, um dann die veränderten Daten mit der DOM-Deserialisierung wieder abzurufen.
namespace Serialisierung {
class Program {
static void Main(string[] args) {
ProductSerializer serializer = new ProductSerializer();
Product product = serializer.
GetProductStandard("SA-M237");
Console.WriteLine("Standardserialisierung");
Console.WriteLine("-----------------------");
Console.WriteLine(
product.Name + " " + product.ProductNumber + " "
+ product.ListPrice);
Console.WriteLine("Aktualisierung");
product.ListPrice = product.ListPrice * 1.4;
product.StandardCost = product.StandardCost * 1.4;
product.Name = product.Name + " New";
serializer.UpdateProduct(product);
Console.WriteLine("-----------------------");
Console.WriteLine("DOM-Serialisierung");
product = serializer.GetProductDOM("SA-M237");
288
Fallbeispiele
Console.WriteLine("DOM - Serialisierung");
Console.WriteLine(
product.Name + " " + product.ProductNumber + " "
+ product.ListPrice);
Console.ReadLine();
}
}
}
Serialisierung/Program.cs: Test von De-/Serialisierung
7.2
Datenaustausch
Neben der zuvor diskutierten Lösung zur (De-)Serialisierung ist vermutlich die Einrichtung einer Import-/Export-Schnittstelle eine häufigere Aufgabenstellung. Sie soll in
diesem Abschnitt diskutiert werden.
7.2.1
Export
Neben dieser speziellen Möglichkeit der Serialisierung sind es vor allen Dingen die
klassischen CSV-basierten Import-/Export-Schnittstellen, welche durch XMLTechniken abgelöst werden. Zunächst soll die allgemeine Architektur des ExportVorgangs beschrieben werden. Die Grundbausteine des gesamten Systems lassen sich
auf der allgemeinen Ebenen der Beschreibung für beide Richtungen nutzen und tauchen
daher sowohl für den Import- als auch für den Export-Vorgang auf.
In der Datenbank selbst befinden sich verschiedene relationale Tabellen, deren Datenbestand im Hinblick auf den Export-Vorgang die Quelle darstellen. Für dieses Ziel kann
zusätzlich auch die Einrichtung einer Sicht mit einer möglichst guten relationalen Abbildung der Zieldatenstruktur oder wenigstens einer zusammenfassenden Struktur hilfreich sein. Diese Sicht ist ebenfalls in der Abbildung oberhalb der beiden Beispieltabellen platziert. In dieser Sicht befinden sich die sich wiederholenden Gruppen von ElternKind-Hierarchien, wenn die beiden Tabellen in einer 1:n-Beziehung zueinander stehen.
In einem 1:1-Fall ist dies natürlich nicht der Fall. Hier würden nur die entsprechenden
Spalten quasi nebeneinander gestellt.
Grundsätzlich muss man unterscheiden, ob der Exportvorgang zu konkreten XMLDokumenten und damit auch Dateien führt, oder ob es sich um reine Datenströme han-
289
Fallbeispiele
delt. Während die Datenströme in jedem Fall nur auf Bedarf erzeugt werden und damit
nicht notwendigerweise mit Hilfe von zeitgesteuerten DB-Jobs erzeugt werden können,
kann hier auch keine zusätzliche Speicherung möglich sein. Daher werden die XMLDatenströme sowohl in Form eines Webservices als auch durch Interaktion mit einem
Formular erzeugt und bereitgestellt. Die Dokumente dagegen werden als physische
Dateien erzeugt und können auf unterschiedliche Weise in einem öffentlichen Ordner(verzeichnis) platziert und damit erneut persistent gespeichert werden. In vielen
Fällen dürften dies auch FTP- oder WebDAV-Ordner sein, die über eine sichere Verbindung genutzt werden können.
Die Abbildung gibt keine Informationen darüber, wie die entsprechenden XML-Daten
tatsächlich erzeugt werden. Dies ist in einer späteren Abbildung thematisiert. Stattdessen teilt ein senkrechter Strich die gesamte Grafik, um die beiden Hemisphären von
zwei Unternehmen zu kennzeichnen. Es muss sich selbstverständlich nicht notwendigerweise um den Austausch von Daten zwischen zwei Unternehmen handeln, sondern
es könnten auch Beziehungen zwischen zwei Abteilungen oder allgemein zwischen
zwei unterschiedlichen Systemen sein.
Auf der Seite von Unternehmen B, welches hier im Rahmen des Export-Vorgangs die
Daten erhält, gibt es ebenfalls unterschiedlich Möglichkeiten, wie die Daten abgerufen
werden. Dies ist im Gegensatz zur Datenerzeugung sehr wohl dargestellt.
1.
2.
290
Im ersten Fall stellt Unternehmen A auch eine Webanwendung zur Verfügung,
welche nach einem entsprechenden Login die Daten quasi zum Download anbietet.
Dabei muss man sich diesen Download durchaus nicht so vorstellen, dass
tatsächlich Dateien aus einem Ordner abgerufen werden, sondern dass die
Benutzeranforderung zu einem Extraktionsvorgang führt, welcher flüchtig einen
Datenstrom erstellt. Hierbei liegt die Softwareentwicklung aufseiten von
Unternehmen A, dem Datenlieferanten, während Unternehmen B nur die von
Unternehmen A bereitgestellten Zugangswege nutzt.
In einem zweiten Fall bietet Unternehmen A einen Webservice an. Dies bedeutet
zwar auch, dass der wesentliche Teil der Softwareentwicklung bzgl. der
Datenverteilung aufseiten von Unternehmen A liegt, doch können die Daten im
Normalfall nur über Software von Unternehmen B auch tatsächlich abgerufen
werden. Hier interagiert ein Benutzer des Zielsystems mit einem von Unternehmen
B erstellten Web- oder Desktopanwendungsformular, welches in Wirklichkeit auf
den Webservice zugreift. Diese Variante erlaubt die gleichen Möglichkeiten und
Alternativen wie durch das direkt von Unternehmen A angebotene Web-Formular.
Auch hier erzeugt Unternehmen A die Exportdaten nicht in Form von Dateien,
Fallbeispiele
3.
sondern nur als flüchtigen Datenstrom. Hier ist ebenfalls eine Benutzerinteraktion
vonnöten, um die Extraktion anzustoßen. Sollte dagegen aus Leistungs- oder
Sicherheitsgründen eine solche unmittelbare Interaktion mit dem Exportmodul
aufseiten von Unternehmen A unerwünscht sein, so bietet sich dennoch eine
Möglichkeit an, über ein selbst erstelltes Formular auf den öffentlichen Ordner von
Unternehmen A zuzugreifen. In einer weiteren Variation lässt sich sogar ein
Webservice denken, welcher Unternehmen B die Möglichkeit bietet, mit einem
solchen Ordner zu interagieren.
In einem dritten Fall wird die gerade eben genannte Möglichkeit noch einmal
deutlicher aufgegriffen. Hier bietet Unternehmen A einen öffentlichen Ordner auf
Basis von FTP, WebDAV oder einem sonstigen Prinzip an, auf den das
Unternehmen B entweder direkt, über ein Formular oder auch über eine ImportSoftware zugreift. Insbesondere die letzte Möglichkeit führt eine weitere
grundsätzliche Variante in diese Architektur ein. Während in den ersten beiden
Fällen zunächst nur ein menschlicher Akteur von Unternehmen B den ImportVorgang für sein Unternehmen durchführte, besteht natürlich sowohl beim
Webservice als auch beim öffentlichen Ordner die Möglichkeit, eine eigene
Software zu verwenden, welche zeitgesteuert oder auf Basis sonstiger Anstöße und
Ereignisse den Importvorgang automatisch durchführt.
Die Erzeugung der XML-Daten ist über unterschiedliche T-SQL-Techniken möglich.
Sie wurden in den vorherigen Abschnitten erläutert und sollen in diesem Zusammenhang für die Realisierung dieser Import-/Export-Schnittstelle noch einmal aufgeführt
werden. Die einzelnen Lösungen haben unterschiedliche Vor- und Nachteile, die teilweise nur auf Grundlage des Zielschemas (Komplexität, Umfang, Tiefe/Hierarchieanzahl) oder der Datenmenge für eine bestimmte Schnittstelle bewertet
und letztendlich auch ausgewählt werden können. In allen Fällen hat man die Wahl, ob
die erzeugte XML-Struktur als Datei gespeichert oder als XML-Datenstrom zurückgegeben wird. Auf die Möglichkeit, einen Webservice oder einen Windows-Dienst/eine
Server-Komponente zu erstellen, wird nicht eingegangen, da dies noch tiefer gehende
Kenntnisse der MS SQL Server-Programmierung erfordert.
291
Fallbeispiele
Unternehmen A
Unternehmen B
Datenbank
Web-Formular
Prozedur
<xml-strom/>
Funktion<xml-strom/>
Benutzer
Web
Service
Sicht
XML
XML
Formular
Benutzer
Tabelle 1
Tabelle 2
FTP-Verzeichnis /
Öffentlicher Ordner
Exportsoftware
Abbildung 4.3: Funktionsweise des Exports
ƒ
ƒ
292
Funktion: Eine Funktion ermöglicht die Erzeugung von XML-Daten mit allen
XML-Techniken von T-SQL und liefert die Daten über einen Rückgabewert
zurück. Sofern die Daten in einem anderen T-SQL-Programm benötigt werden oder
eine Funktion besonders gut zum Einsatz kommen kann, ist dies die richtige Wahl.
Dies ist insbesondere der Fall, wenn eine SQL-Anweisung die XML-Daten liefern
soll und die äußere Anwendung einen solchen Datentyp verarbeiten kann. Die
Übergabe von Parametern für Filter gelingt über die Übergabeparameter.
Prozedur: Eine Prozedur liefert die Daten nur über einen Ausgabe-Parameter. Im
Normalfall gibt es allerdings eine Vielzahl an äußeren Programmier-sprachen,
welche genau diesen Ausgabeparamter viel einfacher abfangen können als den
Rückgabewert einer Funktion. Teilweise ist es auch in der äußeren
Fallbeispiele
ƒ
Programmiersprache einfacher, eine Prozedur aufzurufen als eine Funktion. Die
Übergabe von Parametern für Filter gelingt über die Übergabeparameter.
Sicht: Eine Sicht stellt in Form einer virtuellen Tabelle die Möglichkeit dar, XMLDaten so anzubieten, dass man eine einfache Abfrage nutzen kann. In diesem Fall
muss allerdings sicher gestellt sein, dass die äußere Anwendung dieses
Abfrageergebnis auch verarbeiten kann. Eine Filterung der Daten kann dann über
T-SQL durchgeführt werden, was zu umfangreicheren Filtermöglichkeiten führt als
eine begrenzte Anzahl an Parametern. Durch den Einsatz von T-SQL für die
Filterung können hier fast beliebige Filteranweisungen ad hoc angegeben werden,
die ansonsten in einer Prozedur/Funktion von vorneherein vorbereitet sein müssten.
7.2.2
Import
Der Import-Vorgang ist nicht nur aus einfach nachzuvollziehenden Gründen das zum
Export passenden Pendant. Dieser Umstand wirkt sich auch sehr auf die allgemeine
Architektur der Import-/Export-Schnittstelle aus. In der nachfolgenden Abbildung sind
lediglich die Pfeile in ihrer Richtung vertauscht, und die Grafik erfordert eine andere
Leserichtung, nämlich in diesem Fall von rechts nach links. Bedeutsam ist, dass auf der
einen Seite natürlich auch verschiedene Wege genutzt werden können (Export über
Webservice, Import dagegen über Upload-Formular), dass aber grundsätzlich auch die
Option besteht, beide Vorgänge über den gleichen Kanal durchzuführen, sofern ein
wechselseitiger Datenaustausch überhaupt innerhalb des Systemumfangs liegen soll.
Die drei oben genannten Schnittstellen sind also in auch in dieser Lösung vorhanden.
1.
2.
Im ersten Fall stellt Unternehmen A für den Datenimport eine Web-Anwendung zur
Verfügung, welche nach einem entsprechenden Login die Daten für einen UploadVorgang entgegennimmt. Hier wird vermutlich tatsächlich von Unternehmen B
eine physische Datei erstellt, die das Exportmodul als Variante auch erst im
Rahmen der gesamten Transaktion aus den vorhandenen Daten generiert.
In einem zweiten Fall bietet Unternehmen A einen Webservice an. Dies bedeutet
zwar auch, dass der wesentliche Teil der Softwareentwicklung bzgl. der
Datenverteilung aufseiten von Unternehmen A liegt, doch können die Daten im
Normalfall nur über Software von Unternehmen B auch tatsächlich übertragen
werden. Hier interagiert ein Benutzer des Zielsystems mit einem von Unternehmen
B erstellten Web- oder Desktopanwendungsformular, welches in Wirklichkeit auf
den Webservice zugreift. Diese Variante erlaubt die gleichen Möglichkeiten und
Alternativen wie durch das direkt von Unternehmen A angebotene Web-Formular.
293
Fallbeispiele
Hier erzeugt Unternehmen B die Exportdaten nicht in Form von Dateien, sondern
nur als flüchtigen Datenstrom, der als Webservice-Anfrage verschickt wird.
Alternativ wird er sogar aus Dateien gewonnen. Hier ist gleichfalls eine
Benutzerinteraktion vonnöten, um die Übertragung anzustoßen. Sollte dagegen aus
Leistungs- oder Sicherheitsgründen eine solche unmittelbare Interaktion mit dem
Importmodul aufseiten von Unternehmen A unerwünscht sein, so bietet sich
dennoch eine Möglichkeit an, über ein selbst erstelltes Formular auf den
öffentlichen Ordner von Unternehmen A zuzugreifen. In einer weiteren Variation
lässt sich sogar ein Webservice denken, welcher Unternehmen B die Möglichkeit
bietet, mit einem solchen Ordner zu interagieren und Dateien in diesem Order
abzulegen
3. In einem dritten Fall wird die gerade eben genannte Möglichkeit noch einmal
deutlicher aufgegriffen. Hier bietet Unternehmen A einen öffentlichen Ordner auf
Basis von FTP, WebDAV oder einem sonstigen Prinzip an, auf den das
Unternehmen B entweder direkt, über ein Formular oder auch über eine ExportSoftware zugreift. Insbesondere die letzte Möglichkeit führt eine weitere
grundsätzliche Variante in diese Architektur ein. Während in den ersten beiden
Fällen zunächst nur ein menschlicher Akteur von Unternehmen B den ExportVorgang für sein Unternehmen durchführte, besteht natürlich sowohl beim
Webservice als auch beim öffentlichen Ordner die Möglichkeit, eine eigene
Software zu verwenden, welche zeitgesteuert oder auf Basis sonstiger Anstöße und
Ereignisse den Exportvorgang automatisch durchführt.
Die nachfolgende Abbildung zeigt die unterschiedlichen Varianten anhand der vorher
schon verwendeten Struktur, wobei die einzige Änderung in der Umkehrung der Pfeilrichtung besteht, die den Datenverkehr symbolisieren.
Für die Realisierung einer solchen Import-Schnittstelle lassen sich am besten folgende
Techniken nutzen. Die Realisierung über einen Webservice, eine Server-Komponente
oder einen Windows-Dienst erfordert fortgeschrittene T-SQL/.NET-Kenntnisse und soll
hier nicht behandelt werden.
ƒ
ƒ
294
Prozedur: Eine Prozedur erwartet als Übergabeparameter die XML-Daten und
zerlegt sie relational. Als Ausgabeparameter kann dann eine Erfolgsmeldung
übergeben werden. Im Normalfall ist dies die beste Lösung.
Funktion: Eine Funktion erwartet die Daten ebenfalls als Übergabeparameter, kann
insbesondere auch eine Erfolgsmeldung als Rückgabewert liefern. Sie muss
allerdings in Form eines längeren T-SQL-Skripts genutzt werden und auf der
Fallbeispiele
ƒ
rechten Seite der Zuweisung erscheinen, was nicht immer gewünscht/vorteilhaft
sein wird.
Tabelle: Eine Tabelle kann über einen INSERT-Befehl die XML-Daten erwarten,
validieren und dann speichern. Ein Trigger oder eine weitere Prozedur könnte sie
dann weiter relational zerlegen. Dies erlaubt die Zwischenspeicherung von XMLDaten zur Kontrolle durch einen Benutzer oder eine Automatik, die nicht
unmittelbar mit dem Speichervorgang gleichzeitig abläuft.
Unternehmen A
Unternehmen B
Datenbank
Web-Formular
Prozedur
<xml-strom/>
<xml-strom/>
Funktion
Benutzer
Web
Service
Sicht
XML
XML
Formular
Benutzer
Tabelle 1
Tabelle 2
FTP-Verzeichnis /
Öffentlicher Ordner
Importsoftware
Abbildung 4.4: Import
Die Ausführungen haben vor allen Dingen die einzelnen Wege gezeigt, in denen eine
Übertragung von Daten stattfinden kann und mit welchen Werkzeugen sie tatsächlich
durchgeführt wird. Diese Werkzeuge wurden in anderen Kapiteln schon weitestgehend
295
Fallbeispiele
beschrieben. Sie haben allerdings auch gezeigt, wie viele Untervarianten und zusätzliche Möglichkeiten dem Entwickler bzw. dem Planer offen stehen, eine solche Schnittstelle zu realisieren. Allein solche Überlegungen, wie bei unterschiedlichen ein- oder
ausgehenden Datenströmen ein Zwischenformat zu benutzen, eröffnet eine ganz neue
Dimension der Architektur, die in Abhängigkeit der zu behandelnden XML-Strukturen
sehr viel Arbeit ersparen kann – oder natürlich auch Arbeit bedeuten kann, wenn die
Formate und Algorithmen doch nicht so zahlreich werden wie vorausgesetzt.
7.2.3
Beispiele
Durch die Tatsache, dass der Datentyp xml an jeder Stelle zum Einsatz kommen kann,
an der auch ein anderer Datentyp wie int oder nvarchar zum Einsatz kommen könnte, ergeben sich viele Möglichkeiten, XML-Daten zu liefern, zu speichern oder zu übernehmen Daher sollen die nachfolgenden Beispiele das gesamte Kapitel nur abrunden
und die erwähnte Tatsache noch einmal illustrieren. Andere Beispiele, Funktionen,
Prozeduren oder Sichten zu erstellen, sind auch schon an anderer Stelle gefallen. Die
Möglichkeit, diesen Datentyp als Tabellendatentyp zu verwenden, wurde in jedem Fall
mehrfach vorgeführt, sodass dies in diesem letzten Abschnitt ausfallen kann.
7.2.3.1
Sicht
Eine Sicht kann XML-Daten zurückliefern, wobei man in diesem Fall zwischen einer
Sicht wählen kann, die ausschließlich XML zurückliefert, oder einer solchen, die neben
anderen Spalten mit beliebigen Datentypen auch noch eine oder mehrere XML-Spalten
besitzt. Das nachfolgende Beispiel zeigt eine Sicht, die ausschließlich XML zurückliefert. In diesem Fall ist nicht viel zu tun, außer eine Abfrage zu erstellen, die das gewünschte XML bereitstellt. Insbesondere die Spalte, in der das XML später abgerufen
werden kann, muss namentlich benannt werden, da ansonsten eine Fehlermeldung ausgelöst wird.
CREATE VIEW vProductXML (Product) AS
SELECT ProductID AS ID, Name, Size, ListPrice
FROM Production.Product AS Product
FOR XML AUTO, ROOT('Product-List')
723_01.sql: Erstellung einer Sicht
Diese Sicht lässt sich dann abfragen, wobei in diesem Fall nur ein nvarchar(max)Datentyp in der Spalte Product erzeugt wird, sodass SELECT Product FROM vPro296
Fallbeispiele
ductXML eine lange Zeichenkette und keine Möglichkeit für weitere Einschränkungen
bietet. Man erhält als Ergebnis:
Product
-----------------------------------------------------------<Product-List><Product ID="1" Name="Adjustable Race"
ListPrice="0.0000"/>...
(1 Zeile(n) betroffen)
7.2.3.2
Prozedur
Eine Prozedur kann auf zweierlei Arten mit XML umgehen: entweder liefert sie XML
über einen Ausgabeparameter oder eine Abfrage zurück, oder sie ist in der Lage, XML
über einen Übergabeparameter zu akzeptieren. In diesem letzten Fall könnte man sich –
wie zuvor erläutert – vorstellen, dass mit OPENXML eine relationale Zerlegung in einem
Schritt oder mit sonstigen T-SQL-Anweisungen die Zerlegung in mehreren Schritten
stattfindet. Die nachfolgend erstellte Prozedur liefert wie eine Sicht XML über eine
Abfrage zurück. Wie jeder Prozedur, die eine Ergebnismenge liefert, lässt sich hier sehr
einfach ein Parameter für einen Filter übergeben.
CREATE PROCEDURE pProductXML (@price money) AS
SELECT ProductID AS ID, Name, Size, ListPrice
FROM Production.Product AS Product
WHERE ListPrice <= @price
FOR XML AUTO, ROOT('Product-List')
723_02.sql: Erzeugung einer Prozedur
Diese Prozedur kann dann mit EXEC pProductXML @price = 200 getestet werden
und liefert ein XML-Dokument (keine Zeichenkette) zurück. Man erhält als Ergebnis:
XML_F52E2B61-18A1-11d1-B105-00805F49916B
-------------------------------------------------------------<Product-List><Product ID="1" Name="Adjustable Race"
ListPrice="0.0000"/>...
297
Fallbeispiele
7.2.3.3
Funktion
Eine Funktion kann wie eine Prozedur XML durch einen Übergabeparameter erwarten
und verarbeiten; sie kann jedoch auch XML durch ihren Rückgabeparameter zurückliefern. Dies erfordert lediglich, diesen Datentyp anzukündigen und entsprechende Daten
über die RETURN-Anweisung auch tatsächlich nach einer Abfrage oder einer schrittweisen Zusammensetzung zurückzuliefern.
CREATE FUNCTION fProductXML (
@price money
)
RETURNS XML
AS BEGIN
DECLARE @productList XML
SET @productList = (
SELECT ProductID AS ID, Name, Size, ListPrice
FROM Production.Product AS Product
WHERE ListPrice <= @price
FOR XML AUTO, ROOT('Product-List'))
RETURN @productList
END
723_03.sql: Erzeugung einer Funktion
Diese Funktion lässt sich dann über SELECT dbo.fProductXML(1000) testen und
liefert wie die Prozedur ein XML-Dokument zurück.
298
Herunterladen