Bisherige Teile dieser Lecture
Falls Sie die bisherigen Teile dieser Lecture noch nicht kennen:
- Generische Datenspeicherung mit XML - Teil 1 (Einführung)
 - Generische Datenspeicherung mit XML - Teil 2 (Generic Entity Data Storage)
 
Kurze Rekapitulation was wir machen wollen
Wir wollen also einen ersten Generic Entity Data Storage implementieren, in welchem Generic Entities gespeichert werden sollen. Als Speicherort des Data Storage wählen wir für diesen Teil der Lecture eine XML-Datei. Jetzt schreiben wir also zum ersten mal so richtig Code für unsere Komponente :-)
Übersicht zur geplanten Implementierung
                        Für die Implementierung des Data Storage benötigen wir genau eine Klasse: den
                        GenericEntityXmlFileDataStorage.
                        
                        Diese muss dann das Interface IGenericEntityDataStorage implementieren.
                        Die einzige Information, welche Sie benötigt, ist noch der physikalische
                        Speicherort der Datei inklusive des Dateinamens. Da diese Angabe wesentlich ist
                        für ihr ordnungsgemäßes Funktionieren, werden wir den Dateinamen bereits im Konstruktor
                        als Argument vorsehen
                    
                        Der eigentliche Umgang mit den Daten in der Datei - sprich das Speichern, Finden und
                        Löschen - werden wir mit der LINQ to XML Technologie von .Net
                        implementieren - im Folgenden mehr dazu. Hier jetzt erst einmal die Definition der Klasse
                        GenericEntityXmlFileDataStorage:
                    
                        
                    
Wichtige weitere Frage - wie soll das XML innerhalb der Datei formatiert sein? Hier zunächst einmal zusammengefasst, welche Daten wir speichern wollen: Generic Entities mit den String-Eigenschaften "ApplicationKey", "FullClassName", "EntityId" sowie einem XElement "XmlSerialisierung". Basierend hierauf werden wir ein XML-Schema nehmen, welches dem folgenden Beispiel-XML-Code entspricht:
                        
                            <?xml version="1.0" encoding="utf-8" standalone="yes"?>
                            <GenericEntities>
                            <GenericEntity EntityId="17" ApplicationKey="MyTestApp" FullClassName="foo.User">
                            [Hier steht der serialisierte xml code des Users mit ID 17]
                            </GenericEntity>
                            <GenericEntity EntityId="18" ApplicationKey="MyTestApp" FullClassName="foo.User">
                            [Hier steht der serialisierte xml code des Users mit ID 18]
                            </GenericEntity>
                            </GenericEntities>
                        
                    
Implementierung mit LINQ to XML
Konstruktor
Als erstes betrachten wir den Konstruktor. In diesem legen wir die Datei an, sofern sie noch nicht existiert. Dann laden wir den Datei-Inhalt in ein Objekt der Klasse XDocument
An dieser Stelle einen Hinweis zur Implementierung: Wir werden immer nur komplette GenericEntity-Blöcke innerhalb des XDocuments bearbeiten. Einen kompletten Block einfügen, austauschen oder löschen. Wir werden keine Inhalte der Blöcke bearbeiten. Das macht uns das Arbeiten leichter. Wir können hierzu auf das oberste XElement mit dem Namen "GenericEntities" (siehe oben) aus dem XDocument zugreifen - dieses bietet dann alle benötigen gerade genannten Operationen an
Hier die wesentlichen Code-Segmente des Konstruktors:
                        
                            if (!File.Exists(fileName))
                            {
                            using (FileStream fileStream = File.Open(fileName, FileMode.CreateNew))
                            {
                            using (XmlWriter writer = XmlWriter.Create(fileStream))
                            {
                            writer.WriteStartDocument(true);
                            writer.WriteWhitespace(Environment.NewLine);
                            writer.WriteStartElement("GenericEntities");
                            writer.WriteEndElement();
                            writer.Flush();
                            }
                            }
                            }
                            XDocument Document = XDocument.Load(fileName);
                            var genericEntitiesNodes = from c in Document.Descendants()
                            where c.Name.LocalName == "GenericEntities"
                            select c;
                            foreach (var genericEntitiesNode in genericEntitiesNodes)
                            {
                            XElement GenericEntitiesNode = genericEntitiesNode;
                            break;
                            }
                        
                    
Natürlich sollte es nur 1 XElement "GenericEntities" im XML geben. Die Abfrage mit LINQ to XML gibt allerdings immer eine Liste zurück. Wir nehmen einfach immer das erste Element der Liste ...
Hilfsmethoden
Im nächsten Schritt implementieren wir dann eine Hilfsmethode um ein Generic Entity mithilfe seiner ID-Eigenschaften im XML finden
Hier die wesentlichen Code-Segmente um ein Generic Entity XElement zu finden:
                        
                            var existingItems = from c in GenericEntitiesNode.Descendants()
                            where c.Name.LocalName == "GenericEntity" &&
                            c.Attribute("EntityId").Value == entityId &&
                            c.Attribute("ApplicationKey").Value == applicationKey &&
                            c.Attribute("FullClassName").Value == fullClassName
                            select c;
                            foreach (XElement existingItem in existingItems)
                            {
                            return existingItem;
                            }
                            return null;
                        
                    
Auch hier wieder - es sollte immer nur 1 Element geben. Die Abfrage mit LINQ to XML gibt allerdings immer eine Liste zurück. Wir nehmen einfach immer das erste Element der Liste ...
Speichern, Finden und Löschen
                        Beim den eigentlichen Hauptoperationen des Data Storage - dem Speichern, Finden und
                        Löschen - greifen wir hauptsächlich auf die gerade vorgestellte Hilfsmethode zu.
                        Außerdem benutzen wir die Methoden des Top-XElement "GenericEntitiesNode" um die
                        Operationen durchzuführen. Anschließend machen wir die Änderungen mittels der
                        Save-Methode des XDocuments persistent
                    
Hier die wesentlichen Code-Segmente zum Speichern einer Generic Entity:
                        
                            XElement newItem = new XElement("GenericEntity", ...);
                            XElement existingItem = findExisting(...);
                            if (existingItem == null)
                            {
                            // -> insert
                            GenericEntitiesNode.Add(newItem);
                            }
                            else
                            {
                            // -> update
                            existingItem.ReplaceWith(newItem);
                            }
                            Document.Save(FileName);
                        
                    
... zum Finden einer Generic Entity:
                        
                            XElement existingItem = findExisting(...);
                            if (existingItem != null)
                            {
                            GenericEntity genericEntity = new GenericEntity();
                            genericEntity.ApplicationKey = existingItem.Attribute("ApplicationKey").Value;
                            genericEntity.FullClassName = existingItem.Attribute("FullClassName").Value;
                            genericEntity.EntityId = existingItem.Attribute("EntityId").Value;
                            genericEntity.XmlSerialization = (existingItem.FirstNode as XElement);
                            return genericEntity;
                            }
                            return null;
                        
                    
... und zum Löschen einer Generic Entity:
                        
                            XElement existingItem = findExisting(...);
                            if (existingItem != null)
                            {
                            existingItem.Remove();
                            }
                            Document.Save(FileName);
                        
                    
Damit wären wir fertig mit der Implementierung des Generic Entity Xml File Data Storage. Was noch fehlt ist eine Fehlerbehandlung sowie die Implementierung der restlichen Methoden. Diese erfolgt dann analog den gerade beschriebenen Methoden
Nächster Schritt
Im nächsten Teil der Lecture werden wir einen weiteren Data Storage Typ für Generic Entities implementieren. Dieser wird die Daten dann (nicht persistent) im Arbeitsspeicher speichern - ein Generic Entity Memory Data Storage
... to be continued
- Generische Datenspeicherung mit XML - Teil 4 (Arbeitsspeicher als Generic Entity Data Storage)
 - Generische Datenspeicherung mit XML - Teil 5 (SQL Server als Generic Entity Data Storage)
 - Generische Datenspeicherung mit XML - Teil 6 (Data Storage)
 - Generische Datenspeicherung mit XML - Teil 7 (Data Storage als Web-Service mit WCF)
 - Generische Datenspeicherung mit XML - Teil 8 (Zusammenfassung)
 
Autor: Thomas Gysser | www.advadev.de
Keine Kommentare:
Kommentar veröffentlichen