2
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.

【Entity Framework Core】コードファーストで移行したDBをリバースエンジニアリングして違いを感じる

Posted at

Entity Framework に関する(自分のための)おさらい

ここ最近、Entity Framework Core の機能を試している

  • この記事ではデータベースファースト でモデルの生成をした
  • この記事ではコードファーストで DB を生成した

この記事は

コードファーストでつくったDBを、再度リバースエンジニアリングしてコードに戻すことを試す

そのとき、もとのコードと、リバースエンジニアリングしてきたコードのあいだに、どんな違いがあるのか?
気になったので試して違いを感じる

リバースエンジニアリング先のプロジェクトをつくる

前回は、IntroプロジェクトからコードファーストでDBをつくった
今回は、そのDBをリバースエンジニアリングすることで、モデルとコンテキストをIntroReverseプロジェクトにスキャフォールディングする(用語の使い方が合っているかわからない)

プロジェクトの準備

  1. IntroReverseプロジェクトをつくる
  2. スタートアッププロジェクトの参照にIntroReverseプロジェクトを追加する
  3. EF Core関連の必要なパッケージをインストールする
パッケージマネージャーコンソール
# ライブラリプロジェクトを新規作成する
dotnet new classlib --framework "netcoreapp3.1" -o IntroReverse

# ライブラリプロジェクトをスタートアッププロジェクトの参照に追加する
dotnet sln add .\IntroReverse\IntroReverse.csproj
dotnet add .\WPF_EFCore\WPF_EFCore.csproj reference .\IntroReverse\IntroReverse.csproj

# ライブラリプロジェクトに必要なパッケージをインストールする
dotnet add .\IntroReverse\IntroReverse.csproj package Microsoft.EntityFrameworkCore
dotnet add .\IntroReverse\IntroReverse.csproj package Microsoft.EntityFrameworkCore.SqlServer

DBからスキャフォールディングする

たった 1 行のコマンドで、 DB からモデルとコンテキストを生成できる

パッケージマネージャーコンソール
Scaffold-DbContext  'Data Source="localhost, 11433";Initial Catalog=Blogging;User ID=sa;Password=SqlPass1234' Microsoft.EntityFrameworkCore.SqlServer  -Project IntroReverse -OutputDir Models -ContextDir Context -Context BloggingReverseContext

横スクロールが長いので、主要なパラメータだけ抜粋して表にする

項目 説明
Initial Catalog= Blogging 接続先のデータベースの名前
-Project IntroReverse データベースをもとにモデルとコンテキストを作成する先のプロジェクトの名前
-OutputDir Models フォルダの名前。テーブルのエンティティがここに生成される
-ContextDir Context フォルダの名前。コンテキストのクラスがここに生成される
-Context BloggingReverseContext コンテキストのクラス名

スキャフォールディングした結果

2つのフォルダと、3つの.csファイルが自動生成された

image.png

モデルを比較する

公式ドキュメントのモデルを参考につくったIntro
先ほどリバースエンジニアリングしてつくったIntroReverseを比較する

  • Blogクラス
  • Postクラス
  • BloggingContext/BloggingReverseContextクラス

Blogクラス

  • クラスにpartialが付加された
  • DBのフィールドにならないPost型のコレクションが、ListからICollectionに変更された
  • コンストラクタが新たに追加され、コレクションのインスタンスにHashSetが採用された
  • コレクションにはvirtual修飾子がついた
Blogクラス
- public class Blog
+ public partial class Blog
  {
+     public Blog()
+     {
+         Posts = new HashSet<Post>();
+     }
      public int BlogId { get; set; }
      public string Url { get; set; }
      public int Rating { get; set; }
-     public List<Post> Posts { get; set; }
+     public virtual ICollection<Post> Posts { get; set; }
  }

Postクラス

  • クラスにpartialが付加された
  • DBのフィールドにならないBlog型にはvirtual修飾子がついた
Postクラス
- public class Post
+ public partial class Post
  {
      public int PostId { get; set; }
      public string Title { get; set; }
      public string Content { get; set; }
      public int BlogId { get; set; }
-     public Blog Blog { get; set; }
+     public virtual Blog Blog { get; set; }
  }

BloggingContext/BloggingReverseContextクラス

コンテキストは追加箇所が多い

  • クラスにpartialが付加された
  • 2 つのコンストラクタが追加された
  • DbSet<T>virtual修飾子が追加された
  • optionsBuilderのメソッドを呼ぶ前に、IsConfiguredを確認している
  • OnModelCreatingメソッドでいろいろしている
  • partialOnModelCreatingPartialが追加された
BloggingContextクラス/BloggingReverseContextクラス
- public class BloggingContext : DbContext
+ public partial class BloggingReverseContext : DbContext
  {
+     public BloggingReverseContext() { }
+     public BloggingReverseContext(DbContextOptions<BloggingReverseContext> options) : base(options) { }

-     public DbSet<Blog> Blogs { get; set; }
-     public DbSet<Post> Posts { get; set; }
+     public virtual DbSet<Blog> Blogs { get; set; }
+     public virtual DbSet<Post> Posts { get; set; }
  
      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
-         optionsBuilder.UseSqlServer("Data Source=\"localhost, 11433\";Initial Catalog=Blogging;User ID=sa;Password=SqlPass1234");
+         if (!optionsBuilder.IsConfigured)
+         {
+             optionsBuilder.UseSqlServer("Data Source=\"localhost, 11433\";Initial Catalog=Blogging;User ID=sa;Password=SqlPass1234");
+         }
      }
  
+     protected override void OnModelCreating(ModelBuilder modelBuilder)
+     {
+         modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");
+ 
+         modelBuilder.Entity<Post>(entity =>
+         {
+             entity.HasIndex(e => e.BlogId, "IX_Posts_BlogId");
+ 
+             entity.HasOne(d => d.Blog)
+                 .WithMany(p => p.Posts)
+                 .HasForeignKey(d => d.BlogId);
+         });
+ 
+         OnModelCreatingPartial(modelBuilder);
+     }
  
+     partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
  }

もういっかいDBに戻してみる

BloggingReverseContextの接続文字列をInitial Catalog=BloggingReverse;にして、DBをつくる

コード → DB → コード(さっきみた) → DB(今ここ)

パッケージマネージャーコンソール
Add-Migration -Name InitReverse -Context BloggingReverseContext -Project IntroReverse -StartupProject WPF_EFCore
Update-Database -Project IntroReverse -Context BloggingReverseContext

Visual Stduio で DB 扱うのに必要そうなパッケージを入れる

Powershell
dotnet add .\WPF_EFCore\WPF_EFCore.csproj  package Microsoft.EntityFrameworkCore.Tools
dotnet add .\WPF_EFCore\WPF_EFCore.csproj  package Microsoft.EntityFrameworkCore.Design
# ライブラリプロジェクトにも入れておく

Visual Stduio ツール → SQLサーバーの追加

image.png

localhostのDockerコンテナ PORT 11433 に、BloggingBloggingReverse(さっきつくった)がある

image.png

デザイナーの表示T-SQLの比較

コードファーストのBloggingDBと、コードファースト→リバースエンジニアリング→コードファーストのBloggingReverseDBは、完全に一致しました

Blog
-- Blogging
CREATE TABLE [dbo].[Blogs] (
    [BlogId] INT            IDENTITY (1, 1) NOT NULL,
    [Url]    NVARCHAR (MAX) NULL,
    [Rating] INT            NOT NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC)
);

-- BloggingReverse
CREATE TABLE [dbo].[Blogs] (
    [BlogId] INT            IDENTITY (1, 1) NOT NULL,
    [Url]    NVARCHAR (MAX) NULL,
    [Rating] INT            NOT NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC)
);
Posts
-- Blogging
CREATE TABLE [dbo].[Posts] (
    [PostId]  INT            IDENTITY (1, 1) NOT NULL,
    [Title]   NVARCHAR (MAX) NULL,
    [Content] NVARCHAR (MAX) NULL,
    [BlogId]  INT            NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY CLUSTERED ([PostId] ASC),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [dbo].[Blogs] ([BlogId]) ON DELETE CASCADE
);


GO
CREATE NONCLUSTERED INDEX [IX_Posts_BlogId]
    ON [dbo].[Posts]([BlogId] ASC);

-- BloggingReverse
CREATE TABLE [dbo].[Posts] (
    [PostId]  INT            IDENTITY (1, 1) NOT NULL,
    [Title]   NVARCHAR (MAX) NULL,
    [Content] NVARCHAR (MAX) NULL,
    [BlogId]  INT            NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY CLUSTERED ([PostId] ASC),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [dbo].[Blogs] ([BlogId]) ON DELETE CASCADE
);


GO
CREATE NONCLUSTERED INDEX [IX_Posts_BlogId]
    ON [dbo].[Posts]([BlogId] ASC);

おわりに

コードファーストからのリバースエンジニアリングで逆輸入したコードには
元のコードにいろいろpartialやらvirtualやらコンストラクタが加わっていたけれど
DBにしたらどっちも同じだったということが分かった

2
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
2
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?