shuhelohelo’s blog

Xamarin.Forms多めです.

EF CoreでモデルファーストでDBを扱う手順

www.entityframeworktutorial.net

Entity Framework Core : DbContext

DbContextはDBとのやりとりを担う.

DBのエンティティのインスタンスを取得,保存するためのもの.

DbContextはUnit Of WorkとRepository Patternの考えを組み合わせたもの.

EF CoreのDbContextは以下の役割を果たす.

  1. DBとの接続
  2. モデルとリレーションの設定
  3. DBへのクエリ
  4. DBへのデータの保存
  5. ラッキングの変更
  6. キャッシュ
  7. トランザクションの管理

アプリケーションでDbContextを使用するには,DbContextを継承したクラスを作る必要があり,Contextクラスと言われる.

ContextクラスはしばしばDbSetプロパティを含み,それぞれモデルのエンティティに対応する.

以下のContextクラスの例について考える.

public class SchoolContext : DbContext
{
    public SchoolContext()
    {
  
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    }
    //entities
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }
} 

SchoolContextクラスはDbContextクラスを継承し,StudentとCourseというDbSetプロパティを含む.

OnConfiguringメソッドとOnModelCreatingメソッドをオーバーライドする.

DBと接続し,StudentやCourseのデータの検索,取得を行うためには,このSchoolContextのインスタンスを生成する必要がある.

OnConfiguring()メソッドによって,DbContextOptionsBuilderを介してContext データソースを選択,設定する.

どのようにDbContextクラスを設定するかはここが参考になる.

OnModelCreating()メソッドによって,ModelBuilderのFluent APIを介してモデルの設定をする.

First EF Core Consoleアプリケーション

ここではコードファーストでのEntity Framework Coreの使い方をステップバイステップ学んでいく.

.NET Core ConsoleアプリケーションをVisual Studio 2017を使って作成する.

.NET Core ConsoleアプリケーションはVS2017かコマンドラインから作成できる.ここではVS2017を使う.

EntityFrameworkCore.SqlServerをNugetでインストールする.

モデルを作る.

        public int StudentId { get; set; }
        public string Name { get; set; }
        [Required]
        public int CourseId { get; set; }
        public Course Course { get; set; }//ナビゲーションプロパティ
    }

    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
        public ICollection<Student> Students { get; set; }//ナビゲーションプロパティ
    }

DbContextを作る

    public class SchoolContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        { 
            optionsBuilder.UseSqlServer(@"Server=.\SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;");
        }
    }

このContextクラスは2つのDbSetプロパティをもち,StudentとCourseはそれぞれStudentsとCoursesというテーブルに対応する.

OnConfiguringメソッドの中で,DbContextOptionsBuilderのインスタンスはどのDBを使用するかを記述するために用いられる.

UseSqlServerメソッドの中の「Server=.\SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;」は接続文字列といい,DBの情報を表す.

Server=は使用するDBサーバーを,Database=は作成するDBの名前,そしてTrusted_Connection=TrueWindows認証モードを表す.

EF Coreはこの接続文字列を使用して,マイグレーション時にDBを作成する.

Contextとエンティティクラスを作成したら,マイグレーションによってDBを作成するときです.

マイグレーション

EF CoreはDBをモデルを介して作成,更新するための複数のマイグレーションコマンドがある.

dotnet ef migrations add CreateSchoolDB

この時点ではDBはまだ作成されていない.

次に,

dotnet ef database update

ここでDBが作成される.

UseSqlServer()メソッドに記述された接続文字列の内容に従ってDBが作成される.

接続文字列はappsettings.jsonなどの設定ファイルに記述してもよいし,直接UseSqlServerメソッドに渡してもよい.

  "ConnectionStrings": {
    "EmployeeDbConnection": "server=(localdb)\\MSSQLLocalDB;database=EmployeeDB;Trusted_Connection=true"
  }

設定ファイル経由の場合は以下のようにUseSqlServerにわたす.

            services.AddDbContextPool<AppDbContext>(
                options => options.UseSqlServer(_config.GetConnectionString("EmployeeDbConnection")));

DbSetプロパティの名前でテーブルが作成される.StudentsやCourses.

以下のようにDBサーバーへ接続すると,DB及びテーブルが作成されていることが確認できる.

ssms

f:id:shuhelohelo:20191110010456p:plain

Visual StudioSQL Server Object Explorer

f:id:shuhelohelo:20191110010434p:plain

DBの読み書き

Entity Framework Coreによるクエリ

書き込み

                var newStudent = new Student
                {
                    Name = "John",
                };

                context.Students.Add(newStudent);
                await context.SaveChangesAsync();

読み込み

EF CoreはLinq-to-Entities(L2E)に新しい機能がある.これはEF 6にはなかったもの.

                var studentsWithSameName = context.Students
                    .Where(s => s.Name == GetName())
                    .ToList();

このようにLinq形式でDBからデータを取得できる.

Eager Loading

レコードのリレーション先のレコードも一括で取得すること.

レコードを取得して,その外部キーを使って別のテーブルから関連するデータを取得すると,すべてのレコードに対して外部キーを使ったクエリが発生してしまう.(N+1問題)

Includeメソッドを使う.

                var studentWithCourse =await context.Students
                    .Include(s => s.Course)
                    .FirstOrDefaultAsync();

ThenInclude

3.1ではナビゲーションプロパティにvirtualをつけなくてもいい?