ラベル LINQ の投稿を表示しています。 すべての投稿を表示
ラベル LINQ の投稿を表示しています。 すべての投稿を表示

2012/09/04

【LINQ】匿名化した固まりをまるごとグループ化【C#】

 なんのこっちゃって感じのタイトルになってしまいましたが、ちょっとLINQでグループ化してたら気がついたことがあったのでメモっときます。…今開発でLINQばっかり書いてるんで記事もLINQが多くなっちゃいますね。
 さて本題ですが、自分今までLINQでグループ化するとき、(こういう言い方が正しいかはわかりませんが、)匿名化した固まりを要素単位まで分解してグループ化してたんですよって言うかそうしないとグループ化できないと思い込んでたんですよ。ところがたまたま固まりごとグループ化してみたらできちゃったんでびっくりってなわけです。どういうことかは以下のサンプルで。

データ
Users
Id
Name

Points
Id
UserId
Point

 見ての通り、UsersとPointsはIdとUserIdで連結可能であり、今回はIdとNameでグループ化し、Pointの合計を求めたいということにします。

今までコード
from p in 
    (from p in users
     join g in points
     on p.Id equals g.UserId
     select new 
     {
        users= p,
        points = g  
     })
group p by new
{
    p.users.Id,
    p.points.Name
} into g
select new
{
    g.Key.Id,
    g.Key.Name,
    Point = g.Sum(p.points.Point)    
}


新しいコード
from p in 
    (from p in users
     join g in points
     on p.Id equals g.UserId
     select new 
     {
        users = p,
        points = g  
     })
group p by p.users into g
select new
{
    g.Key.Id,
    g.Key.Name,
    Point = g.Sum(p.points.Point)    
}


 ちょっと、変化が少なすぎて分かりにくいかもしれませんが、IdとNameを指定してグループ化していたのをusersのみの指定でグループ化を済ましています。まぁグループ化の単位によっては全然使えなかったりするわけですが、頭の片隅には置いておこうと思った次第で…。

 う~ん、毎度このながらなんてセンスのないサンプルでしょうか…。あとテーブルって簡単に横並びにできんもんだろうか…、float組むのはさすがに面倒だし。

デル株式会社

2012/09/01

【LINQ】LEFT OUTER JOIN(左外部結合)の話【C#】

 まぁ、MSDN(方法 : 左外部結合を実行する)見りゃ分かる話ですが一応メモっときます。単純な内部結合の場合は「join~on~equals~」でOKですが、相手先が存在しないの場合でもレコードを取得したい場合は左外部結合が必要となります。
 とりあえずサンプルデータ。
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
};

結果
IDNameCardNo

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)
};

結果
IDNameCardNo

1

Yamada

999999

2

Tanaka

(null)


 この結果って<table>タグで書いてるだけなんで「ほらできた」って言うわけにはいきませんが…。ggとかgggとかってなんやねん?って感じですが、他に良い書き方が思いつかなかったので…。into句とDefaultIfEmptyメソッドを使うことでgggにはUsersテーブルに対して結合されるレコードと存在しないものには初期値が用意されるわけです。その後、select句でnull値を判定することでCardNoにCardNoかnullを代入してます。

 以上、LINQでLEFT OUTER JOIN(左外部結合)を利用する方法でした。

2012/08/28

【C#】LINQPadのご紹介

 手軽さと便利さに感動したのでLINQPadを軽く紹介します。その名の通り、LINQに関連するアプリで、LINQ単体でのテスト・評価を行うことができ、自分のように開発中にLINQの成否に自信がないとか、結果セットが思った通りになっているか気になるって人にとてもおすすめです。上記リンク先からダウンロード&インストールができます。起動画面は下画像のようにいたってシンプルで、データベースを選択し、LINQを書いて実行してみるって感じです。

デフォルト画面
linqpad0

 実行するとLINQの成否だけでなく下画像のように結果セットやラムダ式等も表示してくれます。

結果セットやラムダ式の表示
linqpad1linqpad2


画像では単純なLINQを書いていますが、もっと複雑なLINQを組む時はこれを使うだけで安心感がぐっとアップします。また、一度作成したLINQの式は保存することもできます。

 自分はデータベースでしか使ったことはないのですがWCFデータサービスでも使えるようです。また言語はC#の他にVBとF#等に対応してます。

 表記が英語なのでメニュー等は分かりづらく感じるかもしれませんが、シンプルだし慣れれば大丈夫だと思います。

 以上、LINQPadのご紹介でした。
pagetop