今日のトピック
- ORMについて
ORM(Object-Relational Mapper)について
端的に言うと、オブジェクト指向プログラミングとリレーショナルデータベースを繋ぐ技術である。
参考文献では、「オブジェクトとRDBのテーブルの行を対応付けることだ」と書いてあった。
※ 以下では、EFCoreを用いて説明したいと思う。
なぜORMを使うのか
前回記事では、DBにおけるリレーションについて説明した。
DBにおけるリレーションとは
そこで、こんな疑問が湧いてこないだろうか...
- 「データベースのスキーマを構築するために、アプリケーションコード内にSQLを書く必要があるの?」
- 「関連するデータを取得するために、毎回複雑なJOIN句を含むSQLを書かないといけないの?」
これらの問題を解決し、開発をよりスムーズにしてくれるのが、今回の主題であるORMなのである。
ORMの使用例(EFCore)
ここでは、1対多のリレーションシップについて、ORMを使用した場合のモデル定義と操作を書いてみる。
ORMでのモデル定義と操作
まず、EFCoreでデータベースとやり取りするためのDbContextクラスとエンティティクラスを定義する。
// --- DbContext ---
public class AppDbContext : DbContext
{
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 1対多: Author - Book
modelBuilder.Entity<Author>()
.HasMany(a => a.Books)
.WithOne(b => b.Author)
.HasForeignKey(b => b.AuthorId);
base.OnModelCreating(modelBuilder);
}
}
// --- エンティティクラス ---
public class Author
{
public int AuthorId { get; set; } // 主キー
[Required, MaxLength(100)]
public string Name { get; set; }
public ICollection<Book> Books { get; set; } = new List<Book>(); // ナビゲーションプロパティ
}
public class Book
{
public int BookId { get; set; } // 主キー
[Required, MaxLength(200)]
public string Title { get; set; }
public int AuthorId { get; set; } // 外部キー
public Author Author { get; set; } // ナビゲーションプロパティ
}
- 上記AuthorクラスとBookクラスでは、Author.Books と Book.Author がナビゲーションプロパティとして1対多の関係を示している。Book.AuthorId が外部キー、OnModelCreating でリレーションが設定されている。
- ナビゲーションプロパティとは、エンティティから関連する他のエンティティ(オブジェクト)へアクセスするためのプロパティである。
ある著者の本を全て取得する操作は以下のようになる。
using var dbContext = new AppDbContext(options);
var author = dbContext.Authors
.Include(a => a.Books)
.FirstOrDefault(a => a.Name == "夏目漱石");
if (author != null)
{
foreach (var book in author.Books)
{
Console.WriteLine($"書籍ID: {book.BookId}, タイトル: {book.Title}");
}
}
※ 使用時のメリット、デメリットについては、参考文献や他の資料を参照下さい。
おわりに
間違いがあれば、ご指摘いただけますと幸いです(__)