{the magic lies between the brackets}

Schlagwort: SQL (Seite 1 von 1)

SQL Datenbanken in Windows Phone 8 nutzen

Man kann Daten in Projekten auf vielfältige Arten speichern, eine davon ist die Hinterlegung der Daten in einer Datenbank.
Dazu gibt es in Windows Phone mehrere Optionen. Das bekannteste und weit verbreitetste Datenbank-Datenbanksystem  ist SQLite.
Sie ist open-source und kann kostenfrei in Projekten eingesetzt werden. Zudem hat SQLite den Ruf sehr stabil und schnell zu laufen.

Wieso soll ich denn überhaupt eine Datenbank nutzen?

Das muss man nicht, aber ab einer bestimmten Komplexität der Daten/Informationen, ist eine Datenbank sinniger, als ein „plumpes“ Hinterlegen der Informationen in Dateien, bspw. über XML oder JSON.

Beginnen wir…
Grundsätzlich gibt es eine Vielzahl von Anbietern, welche SQLite Zugriffe bereitstellen, bspw. SQLite-Net, SQLitePCL, uvm…

Ich habe mich für SQLitePCL entschieden, da ich hier den „simplen“ SQL Syntax nutzen kann und nicht – wie bei SQLite-NET – über LINQ gehen muss.

Installieren wir uns nun also SQLitePCL. Hierbei handelt es sich um ein NuGet-Paket, welches wir in VisualStudio mit über den NuGet Paket Manager installieren können.
Hier gibt es zwei Wege:

  • GUI:
    Rechtsklick auf das Projekt -> NuGet-Pakete verwalten.
    Jetzt aktivieren wir auf der linken Seite die Option „Online“ und suchen nach SQLite-PCL. Hier installieren wir die „Portable Class Library for SQLite“.
    Sobald gefunden, installieren wir sie.
  • Kommandozeile (Nuget-Console):
    Wir öffnen die Kommandozeile und geben folgendes ein: Install-Package SQLitePCL

SQLitePCL_Nuget_Install

 

Danach installieren wir noch die benötigte Windows Library „SQLite for Windows Phone“, hierbei handelt es sich NICHT um ein NuGet-Paket sondern eine Windows SDK Extension:

SQLitePCL_SDK_Install.png

 

Nun installieren wir die Library und fügen eine/n Referenz/Verweis unserem Projekt hinzu.

Anschließend können wir endlich anfangen.

Ganz allgemein sieht ein SQLite-Befehl so aus – wie man die Verbindung (conn) aufbaut, erfahrt ihr gleich:

 
                using (var command = conn.Prepare("INSERT INTO MyTable(VALUE1) VALUES (?);"))
                {
                    command.Bind(1, MeinWert); //1-indexed parameter
                    command.Step(); //Absetzen des Befehls an die Datenbank
                }

Grundsätzlich muss man erst einmal eine Datenbank anlegen.

[spoiler title=“Datenverbindung erstellen“ style=“fancy“ anchor=“Datenbank“]

        public DatabaseConn()
        {
            SQLiteConnection conn = new SQLiteConnection("mydatabase.db");
        }

[/spoiler]
Dies legt die Datenbank in einer Datei namens „mydatabase.db“ ab oder öffnet diese.
Jetzt müssen wir – falls noch nicht geschehen – die Datenbank mit Tabellen füllen:
[spoiler title=“Tabellen-Erstellung“ style=“fancy“ anchor=“Tabelle“]

        public void LoadOrCreateDatabase()
        {
            string sql = @"CREATE TABLE IF NOT EXISTS 
                        MyTable
                        (Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                         Header VARCHAR(255),
                         Text VARCHAR(4096),
                         Position INTEGER);";

            using (var statement = conn.Prepare(sql))
            {
                statement.Step();
            }
        }

[/spoiler]

Um Daten aus der Datenbank abzurufen, muss man erstmal differenzieren.

  • Bekommt man einen Datensatz zurück?
  • Bekommt man mehrere Datensätze zurück?

Für den ersten Fall können wir einfach eine Abfrage absetzen und die Spalten des ersten Datensatzes durchlaufen:

[spoiler title=“Select-Einzeldatensatz“ style=“fancy“ anchor=“Einzeldatensatz“]

using (var command = conn.Prepare("SELECT Id, Header, Text, Position FROM MyTable WHERE Id = ?"))
                {
                    command.Bind(1, ID); //Fill the first (one-indexed!) parameter
                    if (command.Step() == SQLiteResult.ROW || command.Step() == SQLiteResult.DONE) // Überprüfe, ob Reihe existiert oder Step ausgeführt
                    {
                        MyTableObject obj= new MyTableObject ()
                        {
                            id = (long)command["Id"],
                            header = (string)command["Header"],
                            text = (string)command["Text"],
                            position = (long)command["Position"]
                        };
                        return obj;
                    }
                }

[/spoiler]

Für den zweiten Fall müssen wir durch alle Zeilen laufen und diese Daten in unsere Objekte laden:

[spoiler title=“Select mehrerer Datensätzen“ style=“fancy“ anchor=“Mehrfachdatensätze“]

                using (var command = conn.Prepare("SELECT Id, Header, Text, Position FROM MyTable "))
                {
                    while (SQLiteResult.ROW == command.Step()) //Solange noch eine Reihe verfügbar ist, mache weiter
                    {
                        MyTableObject obj= new MyTableObject ()
                        {
                            id = (long)command["Id"],
                            header = (string)command["Header"],
                            text = (string)command["Text"],
                            position = (long)command["Position"]
                        };
                        this.list.Add(obj);
                    }
                }

[/spoiler]

Und zu guter Letzt Befehle ohne Rückgabe. Diese sind sehr einfach und lassen sich

[spoiler title=“Befehle ohne Rückgabe“ style=“fancy“ anchor=“Ohne-Rückgabe“]

                using (var command = conn.Prepare("DELETE FROM MyTable WHERE Id = ?;"))
                {
                    command.Bind(1, "MEINWERT");
                    command.Step(); //Absetzen des Befehls
                }

[/spoiler]

Das war’s. Jetzt könnt ihr eure Datenbank füllen und mit ihr arbeiten.

[C#/.NET] – Einführung in LINQ – SQL für Objekte

Seit einiger Zeit ging es in meinen Projekten immer mehr um gute Lesbarkeit des Codes, da die Wartbarkeit der Projekte wichtig war.
Oftmals musste ich in Listen wühlen und bestimmte Items (<T>) bzw. Indices herausfinden.
Früher tat ich das in einfachen for/foreach-schleifen und einer if-Abfrage:

    foreach (Person item in myList)
   {
      if (item.Age == 20)
      {
          n = myList.IndexOf(item);
          break;
      }
   }    

Codemäßig ist dies aber wirklich – nennen wir es mal suboptimal gelöst. (Klar können wir alles gruppieren etc…)

Auf der Suche nach einem besseren Weg meine Arrays und Listen zu durchlaufen fand ich schließlich LINQ im Namespace System.LINQ.

LINQ ist erst ab .NET 3.5 verfügbar, wer LINQ davor nutzen will, kann LINQBridge nutzen, ein Framework, welches alle Standardqueryoperatorionen in .NET Framework 3.5’s Enumerable Klasse reimplementiert.

Ich werde hier nur auf die Query Expressions eingehen. Man kann aber auch Lambda Expressions nutzen, dazu aber ein anderes Mal mehr.

Nun verwenden wir also den Namespace mit der using-Direktive:

 using System.LINQ; 

Vorweg: SQL Wissen ist hier sehr praktisch!

Warum seht ihr hier:

             IEnumerable myQuery =  from m in myFiles
                                    select m.extension; 

Syntaktisch ist LINQ sehr an SQL angelehnt, es wird spezifiert von was die Daten kommen (from) und was ausgegeben wird (select).

In unserem Beispiel habe ich also eine List myFiles und frage das Attribut extension des Objektes T in der Liste ab.

Der Typ IEnumerable muss hier genutzt werden, denn:
   1. Die Abfrage hat als Quelle eine Liste, welche IEnumerable implementiert.
   2. Die Abfrage selbst gibt ein IEnumerable zurück.

Wenn man faul ist, kann man auch implizit deklarieren, mit var.
Der Compiler führt dann die explizite Deklaration durch.

Wer sich in SQL auskennt wird sich jetzt sicher fragen, wie es mit Bedingungen aussieht.
Klar, die gibt es auch. Sonst wäre LINQ wirklich nutzlos:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    select m.extension; 

Hier ist zu beachten, dass immer noch der C#-Syntax gilt – also Vergleichsoperatoren von C# nutzen!

Zudem gibt es natürlich auch Gruppier- und Ordnungsfunktionen:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    orderby m.extension
                                    select m.extension; 

Hier wird also zusätzlich noch alphabetisch geordnet. Ascending/Descending sind natürlich verfügbar.

  orderby m.extension ascending 
  orderby m.extension descending 

Zu guter letzt hat Microsoft auch hier ein tolles Feature aus SQL übernommen, nämlich Joins.
Vom Grundprinzip ist es wieder SQL gleich:

 join "Objekthier" on "Key1" equals "Objekthier.Key2" 

Beispiel:

 join file in FileList on extension.Id equals file.Id 

Ein vollständiges LINQ-Query sieht also beispielweise so aus:

IEnumerable query = (from file in fileList
join ext in extensionList on file.Id equals ext.Id 
where ext.Id == 1 && file.ReadOnly == false
orderby ext.extension ascending
select file); 

Aber Achtung:

Das gejointe Objekt (file) muss sich auf der rechten Seite des equals-Statements befinden, ansonsten schmeißt der Compiler folgenden Fehler:

Name model is not in scope on the left side of equals. Consider swapping the expression on the either side of equals.

WARNUNG: LINQ ist bis zu zwei mal langsamer als for-Schleifen und dient nur zum Aufbau strukturierteren Codes. Meistens ist die Abfrage performancemäßig vergleichbar mit einer foreach-Schleife

OleDB Exception -2147467259

Datenbank “ konnte nicht geöffnet werden. Entweder wird die Datenbank nicht von Ihrer Anwendung erkannt, oder die Datei ist beschädigt.

So lautete die Fehlermeldung, die ich bekam, als ich ein Update-Statement abschicken wollte.

Der Fehlercode lautete: -2147467259

Fieberhaft suchte ich dann nach einer Lösung.
Ist die Verbindung abgebrochen? War OleDBConnection.DataSource nicht richtig angegeben? Eine falsche Version der Datenbank?

All das konnte ich ausschließen, komischerweise funktionierte alles richtig – zumindest vor zwei Stunden noch.

Die Lösung war, und da hilft die Fehlermeldung überhaupt nicht weiter, ein Fehler im SQL-Statement.

Ich hab vergessen die WHERE Clause zu definieren, so hätte ich wohl aus Versehen alle Datensätze überschrieben.

Die Warnung war also doch nicht ganz nutzlos ;)

Warum dieser Fehler erst jetzt auffiel und nicht schon viel länger, bleibt mir allerdings rätselhaft.