0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Xamarin.Forms + Entity Framework Core SQLiteで組みたい場合に最初にやること

Posted at

環境

  • Windows10 Pro (20H2) 64bit
  • Visual Studio 2019 16.8.4
  • Xamarin 16.8.000.261

要約

たまーにXamarin触るんですけど、大体EFCoreとSQLite周りでハマります。
主にMigration出来るようになるまでの手順が分からなくなります。
そろそろプロジェクト作る都度ネットで色々調べて初期設定する状態から卒業したいので、
自分用メモ兼ねて最初の手順をまとめておきます。

手順

Xamarin.Formsのプロジェクトを立てる

image.png
ここは詰まるポイント無し。Visual Studioさんに全投げ。

ModelとDbContext用のプロジェクトを立てる

データベースに保存するテーブル用クラスと、アクセス用DbContextをまとめるDLL用のプロジェクトを作ります。
.NET Standardのクラスライブラリで良いです。
image.png
image.png

Migration用にコンソールアプリのプロジェクトを追加する

Migration実行するときには.NET Coreで動くプロジェクトが必要です。
Xamarinは動かせないので、Migrationをするためだけのダミープロジェクトを追加します。
image.png
image.png

Nugetから必要なパッケージをインストール

Mictosoft.EntityFramework.Core.Sqliteと、Mictosoft.EntityFramework.Core.ToolsをNugetからインストールします。

  • Mictosoft.EntityFramework.Core.Sqlite
    image.png

  • Mictosoft.EntityFramework.Core.Tools
    image.png

Migration用プロジェクトからDLL用プロジェクトを参照設定

image.png
こうやって

image.png
こう。ここも詰まるポイント無しです。

ModelとDbContextを作成する

先に作ったDLL用プロジェクトにModelとDbContextを追加します。
ざっくり書いていきます。

Model\Bookshelf.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace XamaEFCSqlite.Common.Model
{
    /// <summary>
    /// 本棚
    /// </summary>
    public class Bookshelf
    {
        /// <summary>
        /// ID
        /// </summary>
        public Guid BookshelfID { get; set; }

        /// <summary>
        /// 場所
        /// </summary>
        public string Location { get; set; }

        /// <summary>
        /// 容量
        /// </summary>
        public int Capacity { get; set; }

        public IList<Book> Books { get; set; }

        public Bookshelf()
        {
            BookshelfID = Guid.NewGuid();
            Location = string.Empty;
            Capacity = 0;
            Books = new List<Book>();
        }
    }
}
Model\Book.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace XamaEFCSqlite.Common.Model
{
    /// <summary>
    /// 本
    /// </summary>
    public class Book
    {
        /// <summary>
        /// 本ID
        /// </summary>
        public Guid BookID { get; set; }

        /// <summary>
        /// タイトル
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// ページ数
        /// </summary>
        public int PageCount { get; set; }

        public Book()
        {
            BookID = Guid.NewGuid();
            Title = string.Empty;
            PageCount = 0;
        }
    }
}
StoreDbContext.cs
using Microsoft.EntityFrameworkCore;
using System;
using XamaEFCSqlite.Common.Model;

namespace XamaEFCSqlite.Common
{
    public class StoreDbContext : DbContext
    {
        public DbSet<Bookshelf> Bookshelves { get; set; }
        public DbSet<Book> Books { get; set; }
    }
}

とりあえずモデル2つとコンテキストを作りました。

DbContextに細工

MigrationをするためにはDbContextにパラメータなしのコンストラクタと、データベースプロバイダーを構成する手段が必要です。
「データベースプロバイダーを構成する手段」で手っ取り早いのは、OnConfigureをoverrideすることっぽいので、実装していきます。

StoreDbContext.cs
using Microsoft.Data.Sqlite;            //ここを追加
using Microsoft.EntityFrameworkCore;
using System;
using XamaEFCSqlite.Common.Model;

namespace XamaEFCSqlite.Common
{
    public class StoreDbContext : DbContext
    {
        public DbSet<Bookshelf> Bookshelves { get; set; }
        public DbSet<Book> Books { get; set; }

        //--- ここから追加 ---
        const string dbName = "sample.db";
        string dbPath;

        public StoreDbContext() : this(string.Empty) { }

        public StoreDbContext(string DatabasePath)
        {
            dbPath = DatabasePath;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);

            string path = System.IO.Path.Combine(dbPath, dbName);
            SqliteConnectionStringBuilder builder = new SqliteConnectionStringBuilder()
            {
                DataSource = path,
                ForeignKeys = true
            };
            optionsBuilder.UseSqlite(builder.ConnectionString);
        }
        //--- ここまで追加 ---
    }
}

いきなりごっそり増えましたね。
ここは正直有識者がいらっしゃったら是非相談したいポイントです。

SQLiteのプロバイダーを指定するため、OnConfiguring内でUseSqliteしています。
この時、UseSqliteの引数として接続文字列を渡す必要があります。

ファイル名は定数[dbName]に指定してありますが、ファイルを保存しておく場所は実行するOS(AndroidとかiOSとか)によって変わります
その為、コンストラクタでファイルの場所だけ受け取れるようにしておいて、接続文字列を組み立てる際に完全パスに変えています。

そしてMigrationが実行できるように、パラメーターを受け取らないコンストラクタも定義します。
実際のコードの中でパラメーター無しコンストラクタを呼び出すと、ファイルの場所指定が空白のままOnConfiguring→UseSqliteされるので結構ヤバいことになります。変な所にSqliteDB作られるとか、アクセス不可でエラーになるとか……

なので、実際にコード書くときは[Obsolate]付けるとかで対処した方が安全かもしれませんね。
ちなみにMigration実行時はパスとか関係ありません。

ともあれ、これで準備が整いました。

はじめてのMigration

「最初にやること」としては前セクションまでで終わってたりしますが、せっかくなのでMigrationのコマンドもおさらいしておきます。
Migrationクラスを作成するコマンドは

dotnet ef migrations add <Migration名> -s <Migration用プロジェクト名> -p <DLLプロジェクト名>

こんな感じです。今回の構成の場合は

dotnet ef migrations add InitialCreate -s XamaEFCSqlite.MigrationTool -p XamaEFCSqlite.Common

こうですね。
[dotnet ef]コマンドが見つからない的なエラーが出た場合はこの辺とか見てインストールしましょう。
参照設定ちゃんとしてるのに[Could not load assembly 'なんとか'. Ensure it is referenced by the startup project 'かんとか'.]見たいなエラーが出る場合は、一度リビルドすると良いかもしれません。

結果確認!

image.png
出来ました。以降変更がある場合はさっきのコマンドを使ってMigrationクラスを作っていく形になります。

まとめ

いつも困るところをまとめてみました。
一番最初にやる処理ってプロジェクトごとに1回しかやらないので結構忘れがちです。
自分用メモとしてもQiitaは有効だと思うので今後も書いていきます。

//後は文章ちゃんとまとめる能力が欲しい。
//記事作ると大体クソ長になるのやめたい。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?