0
0

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.

SQL Serverにシードデータを与える

Posted at

はじめに

この記事では、Bloggingデータベースをつくった
今回は、Bloggingデータベースにシードデータを与える

データシード処理とは

データシード処理とは、データベースに初期データセットを設定するプロセスのことです。

データベースをつくったタイミングで、そのデータベースにサンプルデータを挿入できるというもの

特にローカルでいろいろ試しているうちは、検証用にデータが必要になることが多いので
あらかじめ任意の初期データセットをセットできると便利でよい

DbContextを継承したクラスを編集する

ここから実際に手を動かす

シードデータを定義するために
DbContextを継承したBloggingContextを編集する

具体的には、基底クラスに用意されているOnModelCreatingメソッドをオーバーライドして処理を置き換える

今回は、Blogクラスには2つのレコード、Postクラスには4つのレコードを、それぞれ初期値として設定する

BloggingContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // BlogSeed
    modelBuilder.Entity<Blog>().HasData(
        new Blog { BlogId = 1, Url = "http://one.com" },
        new Blog { BlogId = 2, Url = "http://two.com" }
        );

    // PostSeed
    modelBuilder.Entity<Post>().HasData(
        new Post { BlogId = 1, PostId = 1, Title = "title11", Content = "content11" },
        new Post { BlogId = 1, PostId = 2, Title = "title12", Content = "content12" },
        new Post { BlogId = 2, PostId = 3, Title = "title23", Content = "content23" },
        new Post { BlogId = 2, PostId = 4, Title = "title24", Content = "content24" }
        );
}

データベースを移行する

次の手順で、データシード処理をデータベースに反映させる

  1. 移行を追加するAdd-Migration
  2. 移行をデータベースに反映させるUpdate-Database

移行を追加するAdd-Migration

コンテキストを編集したので、編集した内容を記録する
(=Add-Migrationで、移行の履歴に追加する)

パッケージマネージャーコンソール
Add-Migration -Name Seed -Context BloggingContext -Project Intro -StartupProject WPF_EFCore

使っているコードは過去記事からの続いているので
このAdd-Migraitonは、Initマイグレーションにつづいて、2回目のマイグレーションとなる

移行の履歴を確認するGet-Migration

Get-Migrationコマンドにより、BloggingContextに関する移行の履歴を確認できる
また、それらの移行がデータベースに反映されているか否かも確認できる

パッケージマネージャーコンソール
Get-Migration -Context BloggingContext -Project Intro -StartupProject WPF_EFCore
# id                  name safeName applied
# --                  ---- -------- -------
# 202108********_Init Init Init        True
# 202109********_Seed Seed Seed       False

InitにつづいてSeedが追加されていることがわかる
この時点ではまだデータベースには変更が反映されていないので、appliedfalseである

ビジュアルで確認すると、プロジェクトのMigrationsフォルダは以下のようになっている

image.png

移行をデータベースに反映させるUpdate-Database

プロジェクト内で完結していたコードの変更を、実際のデータベースに反映させる

パッケージマネージャーコンソール
Update-Database -Context BloggingContext -Project Intro

すでにデータがある場合は失敗するかもしれない

実際にこの記事を書きながら、Update-Databaseをしたところ、下記のようなエラーが出た

Violation of PRIMARY KEY constraint 'PK_Posts'. Cannot insert duplicate key in object 'dbo.Posts'. The duplicate key value is (4).
The statement has been terminated.

Google翻訳

PRIMARYKEY制約「PK_Posts」への違反。オブジェクト 'dbo.Posts'に重複するキーを挿入できません。重複するキー値は(4)です。

たとえば、データベースを新規作成してから、シードを与えるマイグレーションをする間に
マニュアルでレコードを挿入する操作をしていた場合
挿入した(既存の)データと、シードデータの主キーが衝突する可能性があり、上記のようなエラーが出る

Drop-Databaseで解決する

この記事の前段の通り、今回はDockerコンテナのテスト環境を想定しているので、データベースを一から作り直すほうが早い

  • 今からやること → データベースを削除して、まっさらな状態からシード処理が含まれている移行まで進む
  • おまけ → シードデータの主キーを変える(推奨しない)
パッケージマネージャーコンソール
Drop-Database -Context BloggingContext -Project Intro
# Build started...
# Build succeeded.
# 確認
# この操作を実行しますか?
# 対象 "database 'Blogging' on server 'localhost, 11433'" に対して操作 "Drop-Database" を実行しています。
# [Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定では "Y"):y
# Dropping database 'Blogging' on server 'localhost, 11433'.
# Successfully dropped database 'Blogging'.

データベースを削除したところで、もう1度Update-Database

再度データベースをアップデートする
-Migrationオプションで途中の移行先を指定しない限り、最後まで移行が進む

コマンドは既定で最後の移行になります。

Update-Database - Entity Framework Core ツールリファレンス

パッケージマネージャーコンソール
Update-Database -Context BloggingContext -Project Intro
# Build started...
# Build succeeded.
# Applying migration '20210828010156_Init'.
# Applying migration '20210903234151_Seed'.
# Done.

Initが適応され、つづいてSeedが適応され、順番に移行が済んだことがわかる

データベースを確認する

前回と同じ手順をたどって、データベースをテーブルを確認する

データベースに入るまで

Dockerコンテナに入って、さらにデータベースを選択する

Dockerコンテナに入る
docker exec -it sql1 "bash"
$ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -W
データベースを選ぶ
1> USE Blogging;
2> GO
Changed database context to 'Blogging'.

テーブルのデータをみる

Blogsテーブルと、Postsテーブルのそれぞれにシードデータが存在している

Blogsテーブル
1> SELECT * FROM Blogs;
2> GO
BlogId Url Rating
------ --- ------
1 http://one.com 0
2 http://two.com 0

(2 rows affected)
Postsテーブル
1> SELECT * FROM Posts;
2> GO
PostId Title Content BlogId
------ ----- ------- ------
1 title11 content11 1
2 title12 content12 1
3 title23 content23 2
4 title24 content24 2

(4 rows affected)

おわりに

DbContext継承クラスのメソッドに数行追加することで
データベース作成時に初期データを与えることができた

おまけ

すでにデータがある状態で、シードデータを与えるとどうなるか?

既存データとマイグレーション時のシードデータが重複しないように注意してやればUpdateが通るのか?がこの章の目的
「『すでにあるデータ』のキーが既知であること」が前提であり、そんなこといちいち関知できないので。

既存のデータ

Postsテーブル(上)とBlogsテーブル(下)に、それぞれにデータが入っている

image.png

シードデータをあたえる

既存のデータの主キーと重複しないように、シードデータをあたえる

シードデータ:

  • BlogIdは11, 22
  • PostIdは11, 22, 33, 44

結果、既存のデータに加えて、マイグレーションによるデータシード処理がおこなわれた

image.png

つづいてマニュアルでデータを追加する

主キーを指定せず、あらたにデータを追加すると

シードデータの末尾番号からの連番で新規データが追加される

image.png

データ追加のコード
private void Button_CreateNewBlog(object sender, RoutedEventArgs e)
{
    _context.Add(new Intro.Blog() { Url = $"Url{DateTime.Now.Second}" });
    _context.SaveChanges();
}
private void Button_CreateNewPost(object sender, RoutedEventArgs e)
{
    var blogId = _context.Blogs.OrderByDescending(x => x.BlogId).FirstOrDefault().BlogId;

    _context.Add(new Intro.Post() { Title = $"PostTitle{DateTime.Now.Second}", BlogId = blogId });
    _context.SaveChanges();
}

キーが衝突しなければ、データベースにデータが入っている状態でもシードデータをあたえることができるとわかった

以上。

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?