Weiterführende Informationen findet man auf der RavenDB-Webseite, welche zudem auch eine sehr gute Dokumentation enthält:
Um einen RavenDB-Client einbinden zu können, muss eine Solution erstellt werden.
Hierfür wurde eine WPF-Beispielsolution erstellt, welche nach dem MVVM-Pattern entwickelt wurde.
Das Model-View-ViewModel-Pattern ist das State of the Art-Pattern für WPF-Anwendungen. Es wurde bereits in zahlreichen Artikeln beschrieben. Der vorliegende Artikel soll nicht eine weitere Variante sein. Stattdessen wird hier gezeigt, wie sich aus einem ViewModel Datenbankoperationen auf der RavenDB durchführen lassen. Vorweg zeigt der Artikel auch noch einige Tipps zum Erstellen von ViewModel-Klassen und Verwenden von Commands.
namespace WpfAppRavenDb { public class ViewModel : INotifyPropertyChanged { #region Implementation of INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion } }
Alle Besucher dieser Seite, welche kein Interesse an der MMV-Pattern Implementierung haben, können auf Schritt 9 wechseln.
Erstellung des ViewModel:
Das VM ist das Bindeglied zwischen View und Model und bildet somit den Kern des MVVM-Patterns, gewissermaßen den Controller. Das VM kann Eingaben aus dem View entgegennehmen oder mit einem anderen Dienst interagieren, um die Model-Daten an die View weiterzuleiten.
<Window.DataContext> <local:ViewModel /> </Window.DataContext>
Code der View:
Die Bindung des ViewModels an die View erfolt über den DataContext des Windows.
<StackPanel Grid.Column="0" Orientation="Vertical"> <TextBlock Height="20" Text="Liste der Operationen:" /> <ListBox ItemsSource="{Binding Path=OperationMsg}"/> </StackPanel>
Code der View:
Die Seite ist in zwei Spalten eingeteilt. Links ist eine ListBox platziert, welche alle Datenbank-Operationen protokolliert.
<StackPanel Grid.Column="1"> <Button... Command="{Binding Path=CreateCommand}" Content="RavenDB Laden"/> <Button... Command="{Binding Path=ReadCommand}" Content="Default Buch auslesen"/> <Button... Command="{Binding Path=EditCommand}" Content="Vorhandenes Buch verändern"/> <Button... Command="{Binding Path=DeleteCommand}" Content="Vorhandenes Buch löschen"/> </StackPanel>
Code der View:
In der rechten Spalte sind vier Buttons mit Commands definiert. Mit diesen Commands können vier DB-Operationen nach dem Akronym CRUD durchgeführt werden.
Mit CRUD werden die grundlegenden Datenbankoperationen Create (Datensatz anlegen), Read oder Retrieve (Datensatz lesen), Update (Datensatz aktualisieren) und Delete oder Destroy (Datensatz löschen) bezeichnet.
using System; using System.Diagnostics; using System.Windows.Input; namespace WpfAppRavenDb { public class RelayCommand : ICommand { #region Fields readonly Action < object> _execute; readonly Predicate< object> _canExecute; #endregion // Fields #region Constructors public RelayCommand(Action< object> execute) : this(execute, null) { } public RelayCommand(Action< object> execute, Predicate< object> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } #endregion // Constructors #region ICommand Members [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { _execute(parameter); } #endregion // ICommand Members } }
Infrastruktur-Code für die Command-Weitergabe:
RelayCommand _createCommand; public ICommand CreateCommand { get { return _createCommand ?? (_createCommand = new RelayCommand(param => this.Create())); } }
Das ViewModel kann die Commands über folgende Property vom Typ RelayCommand empfangen.
Nach Betätigung des Buttons wird über den Commend die ViewModel-Methode Create aufgerufen.
using System; namespace WpfAppRavenDb { public class BookModel { public int Id { get; set; } public string Title { get; set; } public string ISBN { get; set; } public int Pages { get; set; } public override string ToString() { return String.Format("{0} '{1}' ({2}) has {3} pages", Id, Title, ISBN, Pages); } } }
Code des Models:
Das Model bildet die Datenzugriffsschicht für die Inhalte, die dem Benutzer angezeigt und von ihm manipuliert werden.
In diesem Schritt soll der RavenDB-Client implementiert werden.
Den Client kann man leicht über NuGet laden
DLL für den Client sind hinzugefügt worden.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <books xmlns:xsi="ht tp://www.w3.org/2001/XMLSchema-instance"> <book> <Id>1</Id> <Title>books 1</T> <ISBN>ISBN-123456-01</ISBN> <Pages>201</Pages> </book> <book> <Id>2</Id> <Title>books 2</Title> <ISBN>ISBN-123456-02</ISBN> <Pages>301</Pages> </book> ...
Um Testdaten in der RavenDB speichern zu können, wurden Excel-Daten erzeugt und als XML-Daten abgelegt.
private const string Url = "http://localhost:8080/"; private const string Database = "TestAndreas.Book"; ... private void Create() { const string path = @"Data/BookDb.xml"; OperationMsg.Add(string.Format("Open Path: {0}", path)); var bookList = from c in XElement.Load(path).Elements("book") select c; using (var ds = new DocumentStore { Url = Url }.Initialize()) using (var session = ds.OpenSession(Database)) { var counter = 0; foreach (var bk in bookList) { var book = new BookModel() { Id = int.Parse(bk.Element("Id").Value), Title = bk.Element("Title").Value, ISBN = bk.Element("ISBN").Value, Pages = int.Parse(bk.Element("Pages").Value) }; session.Store(book); session.SaveChanges(); counter++; var id = string.Format("BookModels/{0}", counter); OperationMsg.Add(string.Format("Save Book with ID: {0}", id)); } } }
create - Erzeugen und Speichern von Daten auf der RavenDB:
In der Save-Methode wird die XML-Datei geöffnet und zeilenweise ausgelesen.
Die einzelnen XElement-Objecte werden im Typ BookModel zwischengespeichert und anschließend auf der RavenDB abgelegt.
using (var ds = new DocumentStore { Url = "http://localhost:8080/" }.Initialize()) using (var session = ds.OpenSession("TestAndreas.Book")) {... var book = new BookModel() {... }; session.Store(book); session.SaveChanges(); } }...
Das eigentliche Speichern auf der RavenDB umfasst nur nebenstehende Codezeilen
RavenDB - Neue Datenbank anlegen 1:
Um Daten überhaupt speichern zu können, muss eine RavenDB auf den Rechner vorhanden sein.
RavenDB Download: RavenDB
RavenDB - Neue Datenbank anlegen 2:
Über den Button "New Database" kann eine neue Datenbank erzeugt werden. Diese ist über den lokalen Port 8080 und den vergebenen Namen erreichbar.
Über den Button "RavenDB Laden" werden die Daten in der neu erstellten Datenbank gespeichert.
Über das lokale Web-Interface können die Daten direkt auf der RavenDB angesehen werden.
private void Read() { const string search = "BookModels/5"; using (var ds = new DocumentStore { Url = Url }.Initialize()) using (var session = ds.OpenSession(Database)) { var book = session.Load< BookModel>(search); OperationMsg.Add(string.Format("book with id {0}", search)); OperationMsg.Add(string.Format("book title {0}", book.Title)); OperationMsg.Add(string.Format("book pages {0}", book.Pages)); OperationMsg.Add(string.Format("book isbn {0}", book.ISBN)); } }
Das Auslesen der Daten erfolgt über die RavenDB-Methode Load.
Das Ergebnis des Auslesen ist im Operationsfenster dargestellt und stimmt mit den Werten auf der Datenbank überein.
private void Edit() { const string search = "BookModels/1"; using (var ds = new DocumentStore { Url = Url }.Initialize()) using (var session = ds.OpenSession(Database)) { var book = session.Load< BookModel>(search); OperationMsg.Add(string.Format("book with id {0} edit.", search)); var oldTitle = book.Title; book.Title = "andreas has edit"; session.Store(book); session.SaveChanges(); var renamedBook = session.Load< BookModel>(search); OperationMsg.Add(string.Format("book with id: {0}. new title {1} and old title {2}.", search, renamedBook.Title, oldTitle)); } }
Das Bearbeiten der Daten erfolgt ebenfalls über die RavenDB-Methode Load.
Die Daten werden ausgelesen, bearbeitet und wieder unter der ID gespeichert.
Das Ergebnis des Editierens ist im Operationsfenster dargestellt und in der Datenbank kann man den neuen Buchtitel sehen.
private void Delete() { const string search = "BookModels/10"; using (var ds = new DocumentStore { Url = Url }.Initialize()) using (var session = ds.OpenSession()) { var book = session.Load< bookmodel>(search); if (book == null) OperationMsg.Add(string.Format("book not found, book with ID: {0}", search)); OperationMsg.Add(string.Format("delete book with ID: {0}", search)); session.Delete(book); session.SaveChanges(); var renamedBook = session.Load< bookmodel>(search); OperationMsg.Add(renamedBook == null ? string.Format("Book with id {0} not found", search) : string.Format("Book with id {0} found! Not delete.", search)); } }
Das Löschen der Daten erfolgt über die RavenDB-Methode Delete.
Auf der Datenbank kann man sehen, dass das Buch mit der ID BookModels/10 fehlt.
Die Verwendung der NoSQL-Datenbank RavenDB gestaltet sich für einen ersten Einstieg einfach, aber die sehr gute Dokumentation auf der Herstellerseite erleichert auch die Verwendung bei komplexeren Aufgaben.
Dieser Artikel soll ein erste Einstieg in die Thematik sein und zeigt die einfachste Verwendung.
Die Bearbeitung/Veränderung der Daten erfolgt hierbei ausschließlich im C#-Code, weil hier eine vollständige Testabdeckung erreicht werden kann.