とりあえずサンプルデータ。
Users
| ID | Name |
|---|---|
1
|
Yamada
|
2
|
Tanaka
|
Cards
| ID | UserId | CardNo |
|---|---|---|
1
|
1
|
999999
|
相変わらず手抜きなデータですが、見ての通りUsersテーブルには2つのレコードがありますが、Cardsテーブルに一つのレコードしかありません。
これを内部結合すると…。
コード
from p in Users
join g in Cards
on p.Id equals g.UserId
select new
{
p.Id,
p.Name,
g.CardNo
};
結果
| ID | Name | CardNo |
|---|---|---|
1
|
Yamada
|
999999
|
当然ながら結合可能なのはYamadaさんのみなのでそれしか表示されません。んでここから本題。Cardsテーブルが結合できんくてもとにかくUsersテーブルにあるレコードは全件引っ張りたいんだけどって場合にどうするかという話です。そこで登場するのがLEFT OUTER JOIN(左外部結合)ってわけです(何か話がSQLの初歩をやってる感じになってますが、まぁいいかってことで…)。
LINQで左外部結合を実現する場合、簡単に言ってしまえばDefaultIfEmptyメソッドを利用し、存在しないものにnull値を割り当ててもらっちゃいます(こんな表現で正しいのか?)。
早速、実験します。
コード
from p in Users
join g in Cards
on p.Id equals g.UserId into gg
from ggg in gg.DefaultIfEmpty()
select new
{
p.Id,
p.Name,
CardNo = (ggg != null ? ggg.CardNo : null)
};
結果
| ID | Name | CardNo |
|---|---|---|
1
|
Yamada
|
999999
|
2
|
Tanaka
|
(null)
|
この結果って<table>タグで書いてるだけなんで「ほらできた」って言うわけにはいきませんが…。ggとかgggとかってなんやねん?って感じですが、他に良い書き方が思いつかなかったので…。into句とDefaultIfEmptyメソッドを使うことでgggにはUsersテーブルに対して結合されるレコードと存在しないものには初期値が用意されるわけです。その後、select句でnull値を判定することでCardNoにCardNoかnullを代入してます。
以上、LINQでLEFT OUTER JOIN(左外部結合)を利用する方法でした。