かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

UWPでSQLiteを使う 準備編

UWPでのデータベースといったらSQLiteといった感じです。小規模なら、クラスのインスタンスをそのままJSON.NETでさくっとシリアライズ・デシリアライズでいいですが、データ量がちょっと多くなってくると、いつ終了してもいいように備えないといけないUWPでは、いちいち全部保存というのも頂けない感じになってきます。

ということでDBを使いましょう。

プロジェクトの作成

UWPのプロジェクトを作成しておきまず。

DBアクセス用ライブラリ

SQLiteをいい感じに使えるようにしてくれるライブラリです。正式リリースされてないEntity Framework Core 1.0か、SQLite.NETのPCL版を使うのがいいと思います。ここでは将来性を買って、Entity Framework Core 1.0のRC1を使っていってみようと思います。

NuGetでプレリリースを含めるを選択して以下のパッケージをインストールします。

  • EntityFramework.SQLite
  • EntityFramework.Commands

RC版の制限事項に依存する設定

.NET Nativeと相性が悪いところが今の段階ではあるみたいで、それを解決するためにおまじないを追加しないといけません。PropertiesのDefault.rd.xmlに対して、以下の1行を追加します。

<Type Name="System.Collections.ArrayList" Dynamic="Required All" />

追加する場所はAdd your application specific runtime directives here.というのが書いてあるしたになります。追加したファイルは以下のようになります。

<!--
    This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
    developers. However, you can modify these parameters to modify the behavior of the .NET Native
    optimizer.

    Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919

    To fully enable reflection for App1.MyClass and all of its public/private members
    <Type Name="App1.MyClass" Dynamic="Required All"/>

    To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
    <TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />

    Using the Namespace directive to apply reflection policy to all the types in a particular namespace
    <Namespace Name="DataClasses.ViewModels" Seralize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <!--
      An Assembly element with Name="*Application*" applies to all assemblies in
      the application package. The asterisks are not wildcards.
    -->
    <Assembly Name="*Application*" Dynamic="Required All"/>
    
    
    <!-- Add your application specific runtime directives here. -->
    <Type Name="System.Collections.ArrayList" Dynamic="Required All" />

  </Application>
</Directives>

動作確認

以下のようなクラスを定義します。

using Microsoft.Data.Entity;

namespace App47
{
    public class SampleContext : DbContext
    {
        public DbSet<Person> People { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("sample.db");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // PersonのNameを必須入力に
            modelBuilder.Entity<Person>()
                .Property(x => x.Name)
                .IsRequired();
        }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

DBの作成

パッケージマネージャーコンソールで以下のコマンドを実行します。

PM> Add-Migration Sample
To undo this action, use Remove-Migration.

画面

画面を作ります。

<Page x:Class="App47.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App47"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView x:Name="ListView">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:Person">
                    <TextBlock Text="{x:Bind Name}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

コードビハインドで、適当にデータを作って読み込む処理を書きます。

using Microsoft.Data.Entity;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace App47
{
    public sealed partial class MainPage : Page
    {

        public MainPage()
        {
            this.InitializeComponent();

            using (var ctx = new SampleContext())
            {
                // どこかでやらないといけないっぽい通常はApp.xaml.csかな
                ctx.Database.Migrate();

                // データ追加
                var people = Enumerable.Range(1, 100).Select(x => new Person { Name = $"tanaka {x}" }).ToArray();
                ctx.People.AddRange(people);
                ctx.SaveChanges();
            }
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            // データを取得してListViewへ
            using (var ctx = new SampleContext())
            {
                this.ListView.ItemsSource = ctx.People.ToArray();
            }
        }
    }
}

実行

実行すると以下のような感じでデータが表示されます。

f:id:okazuki:20160308220554p:plain

まとめ

とりあえずEntity Frameworkを使えば簡単にローカルのSQLiteに繋げることがわかりました。 この調子で使っていこうと思います。