Здравствуй, уважаемый All!

Хочу рассказать о небольшой библиотеке для работы с SQLite в Windows Phone 8.0 Silverlight, Windows Phone 8.1, Windows 8.1 а сейчас еще и для Windows 10 UAP. Библиотеке уже больше года и т.к. проблем с ней за все время не возникло, то, я считаю, о ней можно рассказать другим.

Зачем все это?
Библиотека в рамках Windows Phone 8.0 Silverlight, Windows Phone 8.1, Windows 8.1 просуществовала больше года. Спрашивается: почему именно сейчас я решил о ней рассказать? Дело в том, что сейчас пора портировать свои приложения для Windows 10, а официального SQLite SDK пока нет.
Вот здесь есть SDK для Windows Phone 8, Windows Phone 8.1, Windows 8 и Windows 8.1. Но не для Windows 10.
И скорее всего не будет до выхода Windows 10. Поэтому есть смысл посмотреть на эту библиотеку.

Поехали
Библиотека называется SQLite.WinRT.

Я не являюсь ее 100% автором. Я лишь собрал многие куски кода, блуждающие по интернету, воедино. Поэтому если вы считаете что я как-то нарушил ваши авторские права, то дайте мне знать — договоримся.

Исходные коды можно посмотреть здесь.
Установить библиотеку можно с помощью NuGet. Есть 5 пакетов:

Для успешной компиляции придется избавиться от Any CPU и собирать проект отдельно под каждую платформу: x86, x64, ARM.

Для Windows 10 UAP приложений необходимо добавить ссылку на следующие SDK:
  • Microsoft Visual C++ 14 AppLocal Runtime Package for Windows UAP

Для Windows 8.1 приложений необходимо добавить ссылку на следующие SDK:
  • Microsoft Visual C++ 2013 Runtime Package for Windows
  • SQLite for Windows Runtime (Windows 8.1)

Для Windows Phone 8.1 приложений необходимо добавить ссылку на следующие SDK:
  • Microsoft Visual C++ 2013 Runtime Package for Windows Phone
  • SQLite for Windows Phone 8.1

Для Windows Phone 8.0 приложений необходимо добавить ссылку на следующие SDK:
  • SQLite for Windows Phone


Как использовать библиотеку?
Для примера нам понадобятся следующие классы:
    public sealed class DatabaseContext : BaseDatabaseContext
    {
        private DatabaseContext(SQLiteConnection connection): base(connection)
        {
        }

        public async static Task<DatabaseContext> CreateContext()
        {
            const string dbName = "db.sqlite";

            var folder = CorePlatform.Current.LocalFolder;
            var connectionString = new SQLiteConnectionString(Path.Combine(folder, dbName), true);
            var connection = SQLiteConnectionPool.Shared.GetConnection(connectionString);

            var ctx = new DatabaseContext(connection);
            await ctx.CreateSchemeAsync();
            await ctx.UpdateSchemeAsync();

            return ctx;
        }

        public IEntityTable<Item> Items { get { return provider.GetTable<Item>(); } }
        public IEntityTable<Category> Categories { get { return provider.GetTable<Category>(); } }

    }

    [Table("Items")]
    public class Item
    {
        [PrimaryKey, AutoIncrement]
        public int ItemID { get; set; }
        public int CategoryID { get; set; }
        public string Title { get; set; }
    }

    [Table("Categories")]
    public class Category
    {
        [PrimaryKey, AutoIncrement]
        public int CategoryID { get; set; }
        public string Name { get; set; }
    }


Добавление записи
var category = new Category();
category.Name = "category";
await db.Categories.InsertAsync(category);

Обновление записи
category.Name = "category2";
await db.Categories.UpdateAsync(category);

Обновляются все поля, кроме основного ключа.
Если очень надо, то можно сделать вот так:
var count = db.Categories
  .Update()
  .Set(t => t.Name).EqualTo("test name")
  .Where(t => t.CategoryID).IsBetweenAnd(3, 4)
  .Execute();

В этом случае будет обновлено только то, что будет указано.
Удаление записи
var count = db.Items.Delete()
  .Where(t => t.CategoryID).IsLessThanOrEqualTo(3)
  .And(t => t.Title).IsEqualTo("item0")
  .Execute();

или так:
var category = ...;
await db.Categories.DeleteAsync(category);

Выборка данных
А здесь нам поможет LINQ:
var query =
  from c in db.Categories
  join i in db.Items on c.CategoryID equals i.CategoryID
  select i;

var items = await query.ToListAsync();

Миграция данных
Внимательный читатель заметил 2 интересных вызова:
await ctx.CreateSchemeAsync();
await ctx.UpdateSchemeAsync();

Первый создает или обновляет таблицы на основе объявленных свойств контекста. Колонки в таблице могут быть только добавлены. Удалить нельзя.
Второй запускает список миграций, версия которых меньше версии базы данных.
Объявляются миграции вот так:
    [DatabaseUpdate(typeof(DbChangeset1))]
    [DatabaseUpdate(typeof(DbChangeset2))]
    [DatabaseUpdate(typeof(DbChangeset3))]
    [DatabaseUpdate(typeof(DbChangeset4))]
    public sealed class DatabaseContext : BaseDatabaseContext { ... }

Пример миграции:
    public class DbChangeset1 : IDatabaseChangeset
    {
        public int Version { get { return 1; } }

        public void Update(IEntityProvider provider)
        {
           // так как структура обновляется сама, то тут обновляем только данные.
        }
    }

Вот как-то так. Более подробную информацию можно найти в юнит-тестах.

А теперь я готов выслушать ваши замечания, предложения и возражения.

Комментарии (7)