Windows
.NET
EntityFramework
.NETCore

EntityFrameworkCoreを.NET Core コンソールアプリでCodeFirstに使う

More than 1 year has passed since last update.

執筆時点の環境

  • Windows 10 を使用
  • VisualStudio Community 2017 (略称 VS) インストール済み
  • Microsoft SQL Server Data Tools インストール済み (VSのインストーラに付随)
  • .NET Core 1.0.4
  • EntityFrameworkCore 1.1.2

CodeFirstとは

ソースコードを先に書き、それを元にEntityFrameworkにDB・テーブルを生成させるようなスタイル。ルールに則ってコード記述を行うことでDBやテーブルの生成はフレームワーク側が行ってくれる。

基本ルール

  • エンティティクラス:
    扱うデータを表現するクラス。DBのレコードと対応する。何も継承する必要は無く、カラムと対応するプロパティを持つ。
  • コンテキストクラス:
    DbContextを継承させる。管理するエンティティクラスをDbSet<T>型のプロパティとして保持させる。レコード取得やレコード保存はこのクラスのインスタンスを通して行う。

使ってみる

VisualStudio でプロジェクト作成

テンプレート「.NET Core」-「Console Application (.NET Core)」でプロジェクト作成
(プロジェクト名はHelloCoreとする)

コンソールに日本語を出力すると文字化けする。
.NET Coreは標準ではUnicode, ASCII, CodePage 28591 以外に対応していない一方、WindowsのコンソールはShift-JISである事が原因。NuGet経由でShift-JISへ対応させるパッケージを導入すれば日本語表示可能。以下の作業で対応させる。

NuGetからパッケージ「System.Text.Encoding.CodePages」をインスール
Mainメソッド先頭に以下の記述を追加

Program.cs
        public static void Main(string[] args)
        {
+           //登録すれば必要な場面(Win上で実行した時)で使用されます。
+           System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

EntityFrameworkCoreを使う

SQL Serverと組合せ、指定したフィードから記事タイトルと抜粋を取得しDBへ保存するアプリを作成する。

NuGetで必要パッケージをインストール。

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools

エンティティクラスを作成

データの受け皿となるクラスとしてArticle, AppDbContextを作成。

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace HelloCore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //登録すれば必要な場面(Win上で実行した時)で使用される。
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
        }
    }
    //エンティティクラス
    public class Article
    {
        public int Id { get; set; }
        public string LinkUrl { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string ChannelTitle { get; set; }
    }
    //コンテキストクラス
    public class AppDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            //ここでは接続先のDB名はhellocoredbとする
            optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=hellocoredb;");
        }
        public DbSet<Article> Article { get; set; }
    }
}

VS上で「パッケージマネージャ コンソール」を開く。
コンソールはMicrosoft.EntityFrameworkCore.Toolsによって追加されたコマンドが使用可能になっています。
これを用いてAppDbContextクラスが宣言したDB・テーブルの生成を行う。

PackageManagerConsole
PS> Add-Migration 適当な名前
PS> Update-Database

プロジェクトの/Migrations/下に"適当な名前"のMigration派生クラスが生成される。このクラスの内容が実行されることでDB操作が行われる。上のコマンドではAdd-Migrationで派生クラス生成、Update-Databaseで生成クラスを元にDB操作が行われている。

DB生成を間違えた時は、下記操作を行うとやり直し可能。

  1. プロジェクトへ追加された"Migrations"フォルダを削除
  2. パッケージマネージャコンソールからDrop-Databaseを実行

Mainメソッドで使ってみる

DBの準備は完了。実際にDBを使用してみる。MainメソッドにDBを使用するコードを記述する。

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace HelloCore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
            Console.WriteLine("開始");

            var db = new AppDbContext();
            var http = new System.Net.Http.HttpClient();

            //フィードを適当なサイトから取得
            foreach (var targetUrl in
                new[] {
                    "http://www3.asahi.com/rss/index.rdf",
                    "http://rss.rssad.jp/rss/codezine/new/20/index.xml",
                })
            {
                //フィードxmlをDL & Parse
                //xmlは名前空間で面倒が生じないよう名前空間情報を除染
                var rssTxt = http.GetStringAsync(targetUrl).Result;
                var rss = System.Xml.Linq.XElement.Parse(rssTxt);
                foreach (var item in rss.Descendants())
                    item.Name = item.Name.LocalName;

                //フィードの記事をModelオブジェクトへ移し替える
                var articles = rss
                    .Descendants("item")
                    .Select(item =>
                        new Article()
                        {
                            Title = item.Element("title").Value,
                            LinkUrl = item.Element("link").Value,
                            Description = item.Element("description").Value,
                            ChannelTitle = rss.Element("channel").Element("title").Value,
                        });

                //DBに未追加の記事をDBへ保存する
                foreach (var item in articles)
                {
                    if (db.Article.Any(_ => _.LinkUrl == item.LinkUrl))
                        continue;

                    Console.WriteLine(item.Title);
                    db.Article.Add(item);
                }
            }
            //DBへの保存を確定
            db.SaveChanges();
            Console.WriteLine("終了");
            Console.Read();
        }
    }
    //エンティティクラス
    public class Article
    {
        public int Id { get; set; }
        public string LinkUrl { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string ChannelTitle { get; set; }
    }
    //コンテキストクラス
    public class AppDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            //ここでは接続先のDB名はhellocoredbとする
            optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=hellocoredb;");
        }
        public DbSet<Article> Article { get; set; }
    }
}

VisualStudioで実行。
フィードがコンソールに表示され、VSの「SQL Server オブジェクト エクスプローラ」からhellocoredbのArticleテーブルが更新されている事を確認できれば成功。

その他の操作

エンティティクラスのメンバを編集したい時

エンティティクラスへメンバを編集後、「パッケージマネージャ コンソール」から以下のコマンドを叩く

PackageManagerConsole
PS> Add-Migration 加えた変更が分かる名称
PS> Update-Database

直前の編集を取り消したい時 (DBアップデート前)

以下のコマンドを叩く。DBアップデート後だった場合には取消しマイグレーションとして上の追加時の操作を行う。

PackageManagerConsole
PS> Remove-Migration

DBを消したい時

以下のコマンドを叩く。叩いた後にプロジェクトのMigrationsフォルダを削除

PackageManagerConsole
PS> Drop-Database

おまけ

使用DBをSQLiteに切替えてみる

NuGetから必要パッケージをインスール

  • Microsoft.EntityFrameworkCore.Sqlite

AppDbContextを書き換える

これまではMicrosoft.EntityFrameworkCore.SqlServerの外部拡張メソッドによってSQL Serverを使用するよう設定されていました。Sqlite用を使用するよう書き換えてみます。

Program.cs
public class AppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
        //ここでは接続先のDB名はhellocoredbとする
-       optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=hellocoredb;");
+       optionsBuilder.UseSqlite(@"Data Source='hello.db'");
    }
    public DbSet<Article> Article { get; set; }
}

SQLiteでDBを作成する

PackageManagerConsole
PS> Update-Database

CLI版を使ってみる

こっちの方が好み。

cmd
# CLI版を使う際には追加パッケージをインストールします。
dotnet add package Microsoft.EntityFrameworkCore.Tools.DotNet

# Add-Migration 適当な名前
dotnet ef migrations add 適当な名前

# Remove-Migration
dotnet ef migrations remove

# Update-Database
dotnet ef database update

# Drop-Database
dotnet ef database drop

追加パッケージインストール後には.csprojを開いて入れたパッケージの参照タグの名前を"PackageReference"から"DotNetCliToolReference"に書き換える必要があります。

HelloCore.csproj
    <PackageReference Include="System.Text.Encoding.CodePages" Version="4.3.0" />
-   <PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" />
+   <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" />
  </ItemGroup>
</Project>

まとめ

  • 規約を守った記述を行っていればDB構築はコマンド一本
  • EntityFrameworkCore + SQL Serverで最低限必要なパッケージは無印, Desgin, SqlServer, Tools
  • SQLiteも公式対応。SqlServerの代わりにSqliteパッケージを入れる

参考資料