Entity Framework Core でテーブルのJOIN (テーブル結合)をするコードを紹介します。
概要
Entity Framework Core でテーブルをJOINして対応する値を取得するコードを紹介します。
ヒント
LINQの結果を受け取る際に匿名型を利用しないコードは
こちらの記事を参照してください。
書式
クエリ構文
JOINしすべてのフィールドを取得する場合の書式は以下になります。
結果は匿名型(Anonymous型)で戻るため、
IQueryable<dynamic>
型の変数に代入します。
from (結合元テーブルの一時名) in (結合元テーブルのDbSet) join (結合先テーブルの一時名) in (結合先テーブルのDbSet)
on (結合元テーブルの一時名).(JOIN対象のフィールド) equals (結合先テーブルの一時名).(JOIN対象のフィールド) select new {(結合元テーブルの一時名), (結合先テーブルの一時名)};
メソッド構文
JOINしすべてのフィールドを取得する場合の書式は以下になります。
結果は匿名型(Anonymous型)で戻るため、
IQueryable<dynamic>
型の変数に代入します。
(結合元テーブルのDbSet).Join(
(結合先テーブルのDbSet), (結合元テーブルの一時名) => (結合元テーブルの一時名).(JOIN対象のフィールド),
(結合先テーブルの一時名)=> (結合先テーブルの一時名).(JOIN対象のフィールド),
( (結合元テーブルの返却オブジェクトのフィールド名), (結合先テーブルの返却オブジェクトのフィールド名) ) => new { (結合元テーブルの返却オブジェクトのフィールド名), (結合先テーブルの返却オブジェクトのフィールド名) });
記述例
クエリ構文
IQueryable<dynamic> rec = from pd_table in sc.ProductsDs join pdsp_table in sc.ProductsDstockPlaces
on pd_table.Stockplace equals pdsp_table.Id select new {pd_table, pdsp_table };
メソッド構文
IQueryable<dynamic> rec = sc.ProductsDs.Join(
sc.ProductsDstockPlaces,
pd_table => pd_table.Stockplace,
pdsp_table => pdsp_table.Id,
(pd_table, pdsp_table) => new { pd_table, pdsp_table });
プログラム例
テーブルの準備
データベースに以下のテーブルを用意します。
ProductsD テーブルのstockplace フィールドと ProductsDStockPlace テーブルの id フィールドを結合した結果を取得します。
ProductsD テーブル id | name | stockplace | category | price |
1 | ぺんぎんクッキー | 1 | 1 | 180 |
2 | らくだキャラメル | 3 | 2 | 95 |
3 | しろくまアイス | 2 | 3 | 230 |
4 | かるがもサブレ | 1 | 1 | 160 |
5 | あるぱかカステラ | 2 | 2 | 420 |
ProductsDStockPlace テーブル id | name |
1 | 東京 |
2 | 札幌 |
3 | 福岡 |
Entity Framework Core のインストールとScaffold-DbContext
Entity Framework Coreのパッケージをインストールし、Scaffold-DbContextを実行します。
手順の詳細は
こちらの記事を参照してください。
UI
下図のフォームを作成します。複数行のテキストボックスとボタンを2つ配置します。
コード
以下のコードを記述します。[button1]と[button2]のClickイベントハンドラを実装します。
using EntityFrameworkCoreJoin.Models;
namespace EntityFrameworkCoreJoin
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IQueryable<dynamic> rec;
IPentecSandBoxContext sc = new IPentecSandBoxContext();
rec = sc.ProductsDs.Join(sc.ProductsDstockPlaces, pd_table => pd_table.Stockplace, pdsp_table => pdsp_table.Id, (pd_table, pdsp_table) => new { pd_table, pdsp_table });
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2}\r\n", r.pd_table.Name.Trim(), r.pd_table.Price, r.pdsp_table.Name.Trim());
}
}
private void button2_Click(object sender, EventArgs e)
{
IQueryable<dynamic> rec;
IPentecSandBoxContext sc = new IPentecSandBoxContext();
rec = from pd_table in sc.ProductsDs join pdsp_table in sc.ProductsDstockPlaces on pd_table.Stockplace equals pdsp_table.Id select new { pd_table, pdsp_table };
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2}\r\n", r.pd_table.Name.Trim(), r.pd_table.Price, r.pdsp_table.Name.Trim());
}
}
private void FormMain_Load(object sender, EventArgs e)
{
}
}
}
解説
LINQを利用して、2つのテーブルのJOINを取得します。[button1]がメソッド構文、[button2]がクエリ構文での記述です。
rec = sc.ProductsDs.Join(sc.ProductsDstockPlaces, pd_table => pd_table.Stockplace, pdsp_table => pdsp_table.Id, (pd_table, pdsp_table) => new { pd_table, pdsp_table });
rec = from pd_table in sc.ProductsDs join pdsp_table in sc.ProductsDstockPlaces on pd_table.Stockplace equals pdsp_table.Id select new { pd_table, pdsp_table };
取得した結果をテキストボックスに表示します。
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2}\r\n", r.pd_table.Name.Trim(), r.pd_table.Price, r.pdsp_table.Name.Trim());
}
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
[button1]をクリックします。下図の結果がテキストボックスに表示されます。
ProductsD テーブルのstockplace フィールドと ProductsDStockPlace テーブルの id フィールドが結合でき、
stockplace フィールドに対応する、ProductsDStockPlace テーブルのNameの値を出力できています。
[button2]をクリックします。下図の結果がテキストボックスに表示されます。同じ結果が得られます。
補足
LINQのJOINメソッドの第四引数はテーブルの一時名と合わせなくても良いです。以下のコードでも動作します。
private void button1_Click(object sender, EventArgs e)
{
IQueryable<dynamic> rec;
IPentecSandBoxContext sc = new IPentecSandBoxContext();
rec = sc.ProductsDs.Join(sc.ProductsDstockPlaces, pd_table => pd_table.Stockplace, pdsp_table => pdsp_table.Id, (a, b) => new { a, b });
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2}\r\n", r.a.Name.Trim(), r.a.Price, r.b.Name.Trim());
}
}
プログラム例2: 3つのテーブルをJOIN
テーブル
3つのテーブルをJOINします。
ProductsD テーブル id | name | stockplace | category | price |
1 | ぺんぎんクッキー | 1 | 1 | 180 |
2 | らくだキャラメル | 3 | 2 | 95 |
3 | しろくまアイス | 2 | 3 | 230 |
4 | かるがもサブレ | 1 | 1 | 160 |
5 | あるぱかカステラ | 2 | 2 | 420 |
ProductsDStockPlace テーブル id | name |
1 | 東京 |
2 | 札幌 |
3 | 福岡 |
ProductsDCategory テーブル id | name |
1 | 焼き菓子 |
2 | 生菓子 |
3 | 氷菓 |
UI
下図のフォームを作成します。ボタンは[button4] [button5]を利用します。
コード
下記コードを記述します。
using EntityFrameworkCoreJoin.Models;
namespace EntityFrameworkCoreJoin
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void FormMain_Load(object sender, EventArgs e)
{
}
private void button4_Click(object sender, EventArgs e)
{
IQueryable<dynamic> rec;
IPentecSandBoxContext sc = new IPentecSandBoxContext();
rec = sc.ProductsDs
.Join(sc.ProductsDstockPlaces, pd_table => pd_table.Stockplace, pdsp_table => pdsp_table.Id, (pd_table, pdsp_table) => new { pd_table, pdsp_table })
.Join(sc.ProductsDcategories, pd2_table => pd2_table.pd_table.Category, pdcat_table => pdcat_table.Id, (pd2_table, pdcat_table) => new { pd2_table.pd_table, pd2_table.pdsp_table, pdcat_table });
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2} - {3}\r\n",
r.pd_table.Name.Trim(),
r.pd_table.Price,
r.pdsp_table.Name.Trim(),
r.pdcat_table.Name.Trim()
);
}
}
private void button5_Click(object sender, EventArgs e)
{
IQueryable<dynamic> rec;
IPentecSandBoxContext sc = new IPentecSandBoxContext();
rec = from pd_table in sc.ProductsDs
join pdsp_table in sc.ProductsDstockPlaces on pd_table.Stockplace equals pdsp_table.Id
join pdcat_table in sc.ProductsDcategories on pd_table.Category equals pdcat_table.Id
select new { pd_table, pdsp_table, pdcat_table };
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2} - {3}\r\n",
r.pd_table.Name.Trim(), r.pd_table.Price, r.pdsp_table.Name.Trim(), r.pdcat_table.Name.Trim());
}
}
}
}
解説
LINQを利用して、3つのテーブルのJOINを取得します。[button4]がメソッド構文、[button5]がクエリ構文での記述です。
メソッド構文の場合は、2つのJOINの結果に対して、メソッドチェーンの記述でJOINメソッドを呼び出します。
2番目のJoinメソッドでは、第2引数のパラメーターが、1番目のJoinメソッドの結果となるため、匿名型の構造型 { pd_table, pdsp_table} が入力パラメーターとなる点に注意が必要です。
2番目のJoinの第四パラメーターでは、
new {pd2_table, pdcat_table}
の記述も可能ですが、結果が2段のネストにならないコード記述をしています。
rec = sc.ProductsDs
.Join(sc.ProductsDstockPlaces, pd_table => pd_table.Stockplace, pdsp_table => pdsp_table.Id, (pd_table, pdsp_table) => new { pd_table, pdsp_table })
.Join(sc.ProductsDcategories, pd2_table => pd2_table.pd_table.Category, pdcat_table => pdcat_table.Id, (pd2_table, pdcat_table) => new { pd2_table.pd_table, pd2_table.pdsp_table, pdcat_table });
クエリ構文の場合は、join句を2つ続けて並べ、select句で戻り値の構造を記述します。
rec = from pd_table in sc.ProductsDs
join pdsp_table in sc.ProductsDstockPlaces on pd_table.Stockplace equals pdsp_table.Id
join pdcat_table in sc.ProductsDcategories on pd_table.Category equals pdcat_table.Id
select new { pd_table, pdsp_table, pdcat_table };
LINQで取得したレコードの値を以下のコードでテキストボックスに表示しています。
foreach (var r in rec) {
textBox1.Text += string.Format("{0} \\{1:d} - {2} - {3}\r\n",
r.pd_table.Name.Trim(), r.pd_table.Price, r.pdsp_table.Name.Trim(), r.pdcat_table.Name.Trim());
}
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
[button4]をクリックします。下図の表示結果となります。
ProductsD テーブルのstockplace フィールドと ProductsDStockPlace テーブルの id フィールドが結合され、
ProductsD テーブルのcategory フィールドと ProductsDCategory テーブルの id フィールドが結合でき、
stockplace フィールドに対応する、ProductsDStockPlace テーブルのNameの値と、category フィールドとに対応する、ProductsDCategory テーブルのNameの値が出力できています。
[button5]をクリックした場合も[button4]と同じ結果が表示されます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2023-07-08
作成日: 2023-06-17