[Entity Framework] LINQ で JOIN 等を使わずに複数テーブルからデータを取得する
Entity Framework では、複数のエンティティが 1:N の関係の場合、親エンティティに子エンティティのコレクションを持ち、子エンティティに親エンティティのキーと親エンティティを持つことにより、SQL で行う JOIN などの処理を行わず複数のエンティティからデータを取得することができます。
前提条件
以下の前提条件で動作検証しています。
- Visual Studio Express 2013 for Windows Desktop
- Entity Framework 6.0.2
- SQL Server 2012 Express
- コードファーストのコンソールアプリケーション
Entity Framework 関連
作成するデータベースはブログを想定しています。ブログのポスト(投稿)とコメントを管理します。ポストは Post クラス、コメントは Comment クラスになります。
・Post.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace EFRelation
{
public class Post
{
public int PostId { get; set; }public string Author { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public DateTime Posted { get; set; }
//コメント一覧
//テーブルのフィールドは作成されない
public virtual ICollection<Comment> Comments { get; set; }
}
}
・Comment.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace EFRelation
{
public class Comment
{
public int CommentId { get; set; }public string Author { get; set; }
public string Body { get; set; }
public DateTime Posted { get; set; }
//外部キー
//Post を設定すると自動的に更新される
public int PostId { get; set; }//親フィールド、テーブルには作成されないが
//このフィールドの更新が必要
public virtual Post Post { get; set; }
}
}
テーブルの定義を行うコンテキストクラスを作成する必要があります。
・BlogContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;namespace EFRelation
{
class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }public DbSet<Comment> Comments { get; set; }
}
}
App.config にデータベースの接続文字列を追加します。コンテキストクラスと同じ名前である必要があるので注意してください。
・App.config
<connectionStrings>
<add name="BlogContext"
connectionString="Data Source=(local)\SQLEXPRESS;Initial Catalog=Blog;Integrated Security=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
データ更新・参照プログラム
データを更新・参照するプログラムは以下のようになります。
コメント追加時に、Post クラスのインスタンスを設定しているところがポイントです。他の注意点は、各クラスのフィールドにコメントしてあります。
・Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;namespace EFRelation
{
class Program
{
static void Main(string[] args)
{
//データベース初期化
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BlogContext>());using (var context = new BlogContext())
{
var post1 = new Post(){
Author="山田太郎",
Title="いい天気",
Body="こんにちは。いい天気です。",
Posted = DateTime.Now};context.Posts.Add(post1);
var comment1 = new Comment() {
Author = "山田花子",
Body ="こんにちは",
Posted = DateTime.Now,
Post = post1};context.Comments.Add(comment1);
var comment2 = new Comment() {
Author = "佐藤次郎",
Body = "よろしくお願いします。",
Posted = DateTime.Now,
Post = post1};context.Comments.Add(comment2);
context.SaveChanges();
var posts = from t in context.Posts
orderby t.PostId
select t;foreach (var post in posts)
{
Console.WriteLine("[Post]");
Console.WriteLine(post.PostId.ToString());
Console.WriteLine(post.Author);
Console.WriteLine(post.Title);
Console.WriteLine(post.Body);
Console.WriteLine(post.Posted.ToLongDateString());foreach (var comment in post.Comments)
{
Console.WriteLine("[Comment]");
Console.WriteLine(comment.CommentId.ToString());
Console.WriteLine(comment.Author);
Console.WriteLine(comment.Body);
Console.WriteLine(comment.Posted.ToLongDateString());
}
}Console.ReadKey();
}
}
}
}
実行結果は以下のようになります。
[Post]
1
山田太郎
いい天気
こんにちは。いい天気です。
2014年1月4日
[Comment]
1
山田花子
こんにちは
2014年1月4日
[Comment]
2
佐藤次郎
よろしくお願いします。
2014年1月4日
JOIN を記述していないのに、Posts と Comments の複数テーブルからデータを取得できていることが分かります。
まとめ
Entity Framework では、エンティティの関連を設定し、ルールに従ってデータ更新すれば、JOIN を使わなくても複数テーブルからデータを取得することができることが分かりました。
若干、慣れが必要ですが、コードがシンプルになるのはいいですね。
この方法だと、パフォーマンスがあまりよくないようです。パフォーマンスを改善する方法を関連エントリーに載せたのでご参照ください。
関連エントリー
参考サイト
スポンサーリンク
Twitter ではブログにはない、いろんな情報を発信しています。
@fnyaさんをフォロー
コメント