niedziela, 27 marca 2011

SqLite w .NET

Dziś coś o bazie danych - SqLite. Z pewnością niewielu z Was spotkało się z tą bazą, a Ci którzy spotkali się z nią najczęściej szybko ją porzucają dla komercyjnych baz typu Oracle, MS SQL czy PostgreSql.

Prawdą jest, że w większości systemów z którymi pracuje na co dzień opartych jest na którymś z komercyjnych silników bazodanowych (najczęściej Oracle, MS SQL), jednak warto baczniej przyjrzeć się bazie SqLite.

Na początek słów kilka o samej bazie danych:
Zalety:
- rozmiar: około 300 kB
- napisana w C
- brak dodatkowego procesu zarządzającego relacyjną bazą danych
- zero konfiguracji - nie instalujemy jej, brak potrzeby zarządzania przez administratora
- implementuje większość standardu SQL92
- cała baza danych w jednym pliku (do 2TB)
- zapewnia transakcyjność (ACID)

Wady:
- niepełne wsparcie dla instrukcji ALTER TABLE - brak możliwości modyfikowania istniejących pól, oraz ich usuwania
- staje się coraz wolniejsza dla dużych baz danych (zauważalnie powyżej 2GB)
- odczyt może prowadzić wiele procesów na raz, jednak zapis może być prowadzony tylko przez jeden proces na raz (zakładany jest look na bazę danych).

Podsumowując, jak na wady i zalety nie jest tak źle. Wielu producentów korzysta z tej bazy jako alternatywy dla plików konfiguracyjnych np: Adobe, Firefox, McAfee, Skype itd...

W mojej opinii baza sprawdza się świetnie zwłaszcza w dwóch płaszczyznach: małe aplikacje desktopowe, niewielkie witryny (nie potrzebujemy nawet konta oferującego bazę danych), wersje demonstracyjne systemów. Ostatnie zastosowanie wydaje się bardzo kuszące. Jak wiadomo, klient zanim coś kupi - chce to zobaczyć. W łatwy sposób można przygotować aplikację demo, która pokaże w jaki sposób działa system a przy okazji nie zmusi do wielogodzinnego konfigurowania Oracla czy innego systemu bazodanowego. Po prostu wysyłamy exe wraz z bazą SqLite a klient od razu może przyjrzeć się naszej aplikacji.

Aby skorzystać z dobrodziejst SqLite w .NET potrzebujemy odpowiedniego providera dla tej bazy. Nie ma sensu pisania własnego gdyż istnieje już gotowy - zalecany przez twórców bazy. Pobrać go możemy ze strony http://sqlite.phxsoftware.com/ Po zainstalowaniu mamy do dyspozycji przestrzeń System.Data.SQLite gdzie znajdują się odpowiednie klasy do pracy z naszą bazą danych. Tworzenie pliku bazy danych po instalacji bazy możliwe jest zarówno poprzez dołączony do bazy shell jak i poprzez wygodny wizualny edytor Visual Studio:




Cała praca z bazą SqLite nie odbiega znacząco od pracy z innymi bazami danych. W zależności od tego w jaki sposób pracujemy z bazą danych tworzymy połączenie odczytujemy dane, zamykamy połączenie. 


Przykład:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;
using System.Configuration;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //1. Odczyt danych:
            ConnectionStringSettings connstring = ConfigurationManager.ConnectionStrings["db"];
            using (SQLiteConnection conn = new SQLiteConnection(connstring.ConnectionString))
            {
                using (SQLiteCommand cmd = new SQLiteCommand(conn))
                {
                    conn.Open();
                    cmd.CommandText = "SELECT firstName, lastName FROM person";
                    using (SQLiteDataReader dr = cmd.ExecuteReader())
                    {
                        while (dr.Read())
                        {
                            Console.WriteLine(dr["firstName"]);
                            Console.WriteLine(dr["lastName"]);
                        }
                    }
                }
            }

            //2. Zapis do bazy
            using (SQLiteConnection conn = new SQLiteConnection(connstring.ConnectionString))
            {
                using (SQLiteCommand cmd = new SQLiteCommand(conn))
                {
                    conn.Open();
                    cmd.CommandText = "INSERT INTO person(firstName, lastName) VALUES(@firstName, @lastName)";
                    cmd.Parameters.AddWithValue("@firstName", "Jan");
                    cmd.Parameters.AddWithValue("@lastName", "Kowalski");
                    cmd.ExecuteNonQuery();
                }
            }

            //3. Usuwanie danych z bazy
            using (SQLiteConnection conn = new SQLiteConnection(connstring.ConnectionString))
            {
                using (SQLiteCommand cmd = new SQLiteCommand(conn))
                {
                    conn.Open();
                    cmd.CommandText = "DELETE FROM person WHERE lastName='@lastName')";
                    cmd.Parameters.AddWithValue("@lastName", "Kowalski");
                    cmd.ExecuteNonQuery();
                }
            }

            //4. Aktualizacja danych
            using (SQLiteConnection conn = new SQLiteConnection(connstring.ConnectionString))
            {
                using (SQLiteCommand cmd = new SQLiteCommand(conn))
                {
                    conn.Open();
                    cmd.CommandText = "UPDATE person SET firstName='@firstName' WHERE lastName='@lastName')";
                    cmd.Parameters.AddWithValue("@lastName", "Kowalski");
                    cmd.Parameters.AddWithValue("@firstName", "Marek");
                    cmd.ExecuteNonQuery();
                }
            }
        }
    }
}



Warto zapamiętać, że jeżeli tworzymy kod, który ma za zadanie działać na wielu rekordach na raz, należy zawsze używać transakcji. Nie używając transakcji operacja wstawiania rekordów może trwać nawet 10 razy dłużej! Przykład zaczerpnięty z podręcznika SqLite:

            using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
            {
                int n;

                for (n = 0; n < 100000; n++)
                {
                    mycommand.CommandText = String.Format("INSERT INTO [MyTable] ([MyId]) VALUES({0})", n + 1);
                    mycommand.ExecuteNonQuery();
                }
            }

kod powyżej powinien zostać zastąpiony (i zapomniany) następującym:
            using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
            {
                using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
                {
                    SQLiteParameter myparam = new SQLiteParameter();
                    int n;

                    mycommand.CommandText = "INSERT INTO [MyTable] ([MyId]) VALUES(?)";
                    mycommand.Parameters.Add(myparam);

                    for (n = 0; n < 100000; n++)
                    {
                        myparam.Value = n + 1;
                        mycommand.ExecuteNonQuery();
                    }
                }
                mytransaction.Commit();
            }


W kolejnym poście pokażę przykładową (realną) aplikację napisaną z użyciem powyższej bazy danych.

Brak komentarzy:

Prześlij komentarz