LINQでn:nテーブルを階層オブジェクトに抽出する方法

このQ&Aのポイント
  • LINQを使用して、会員と種別のn:n関係を持つテーブルから階層オブジェクトを抽出する方法を教えてください。会員を表すMembersテーブル、種別を表すTypesテーブル、会員と種別を結び付けるMemberTypeBindsテーブルがあります。
  • LINQを使用してMemberTypesクラスオブジェクトに抽出したい場合、MemberTypesクラスにはMemberオブジェクトとTypeのリストが含まれます。
  • 具体的なLINQのコード例がわからないため、GroupByメソッドを使用してMemberTypeBindsをグループ化するところまではできましたが、その後の階層オブジェクトを生成する方法がわかりません。お手数ですが、詳しい方にアドバイスをいただけますと幸いです。
回答を見る
  • ベストアンサー

LINQでn:nテーブルを階層オブジェクトに

お世話になっております。 表題のテーマについて、理解いただける方にアドバイスお願いします。 会員を表すMembersというテーブル、 種別を表すTypesというテーブル、 会員と種別を結び付けるMemberTypeBindsというテーブルがあって、会員・種別がn対nで定義されています。 Membersの件数は200件ほど、Typeは20件程度。だいたいMembersは1~5くらいのTypeに紐づいています。 Table Members int ID(主キー, autoIncrement) varchar(20) MemberName Table Types int ID(主キー, autoIncrement) varchar(20) TypeName Table MemberTypeBinds int memberID(外部キー, MembersのID) int typeID(外部キー, TypesのID) これを、LINQで下記のクラスオブジェクトに抽出したいと思っています。 今は全件表示でもいいですが、そのうちページングで表示する必要がでてくると思います。 public class MemberTypes {  public Member member { get; set; }  public List<Type> types { get; set; } } どうやるかがわかりません。LINQはこんな感じだと思うのですが、 public List<MemberTypes> GetMemberTypes(){  using (var dc = new DataContext()){   var result = dc.MemTypeBinds    .GroupBy(mt=>mt.Member)    // このあと、どうやったらいいかがわかりません。    // DBから階層化オブジェクトを生成するのは    // けっこう頻出のテーマだと思うので、しっかりマスターしたいです。   }).ToList();   return result;  } } LINQに詳しい方、お助けください。

質問者が選んだベストアンサー

  • ベストアンサー
  • shockatz
  • ベストアンサー率80% (153/191)
回答No.1

ここでLINQについて質問しても回答は出ないのでは。 C#カテのほうが向いてると思うよw LINQは本当に便利。取得だけならSQLなど一行も書く必要ないし、オブジェクトに詰める手間もいらない。 キモは、Group化してまとめたボディ部を、Selectで別の型に変えるところでしょう。 public List<MemberTypes> GetMemberTypes(){  using (var dc = new DataContext()){   return dc.MemTypeBinds    .GroupBy(mt=>mt.Member)    .Select(g=>new MemberTypes{     member = g.Key,     types = g.Select(mtg=>mtg.Type).ToList()    }).ToList();  } } 逆の種別->メンバー(複数)変換も書いてみたww public List<TypeMembers> GetTypeMembers() {  using (var dc = new DcHealth()) {   return dc.MemTypeBinds    .GroupBy(mt => mt.Type)    .Select(g => new TypeMembers {     type = g.Key,     members = g.Select(mtg => mtg.Member).ToList()    }).ToList();  } } 面白いwww

nayutax
質問者

お礼

shockatzさま、正月早々ありがとうございます。 感謝感激です。 members= g.Select(mtg => mtg.Member) のところが本当に感心しました。GroupByすると、なんか変なクラス(IGrouping)に変換されてしまっていて、手も足も出なかったのですが、これなら何にでも応用できますね! SQLのパラメタクエリで、長いSQLCommandを書くのが苦痛で苦痛で仕方なかったので、本当に嬉しいです。 LINQやEFについて、また質問させてください。よろしくお願いします。 (@IT会議室での御礼も含めまして)本年もよろしくお願い申し上げます。

関連するQ&A

  • C#で、LINQを使ってデータベースに書き込みたい

    C#で、LINQを使ってデータベースに書き込みたい LINQに関して、全くの初心者なのでお手柔らかにお願いします。 データベースのテーブル "A" の中身は、 id (string型) hoge (string型) 以上の二つ。 このテーブルに対して、データを書き込むには using (var db = new DataContext()) { db.Log = Console.Out; var storSales =db.A.Select(st => new { st.id, st.hoge }); } このような感じではないかと思いましたが、全然、分かりません。 SQLの構文も分からないのも、起因していますか・・・。 id と hoge にデータを書き込むには どのようにしたらいいでしょうか。 また、参考になりそうなWebページや、お勧めの参考書も教えてください。 以上、よろしくお願いします。

  • テーブル自体のバックアップ

    教えてください。 今オラクルのDBにTEST1テーブルが存在するとします。 ------TEST1--------------------- id varchar(5) Primary Key name varchar(20) old int -------------------------------- 今このテーブルとまったく同じデータを持ち、同じ構成のテーブルTEST2を 作成したいと考えています。 (1)create table TEST2( id varchar(5) primary key, name varchar(20), old int ); (2)insert into TEST2( id, name, old) values (select id, name, old from TEST1); としてTEST2テーブルを作成して、TEST1のデータを格納していますが、 他の方法はないでしょうか? たとえばこんなコマンドはありませんが、 COPY TEST1 TEST2 とか、 オラクルマネージャみたいなもので、 コピペして、名前をTEST2にする とかなんでもいいです。 TEST1のバックアップをとりたいのですが・・・・ すみません、わかりづらい説明で。 宜しくお願い致しますm(_ _)m

  • 同じ構成の2つのテーブルの更新について

    はじめまして、下のような2つの同じ構成のテーブルがあった場合に create table test1 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test1_key primary key (key1,key2,key3,key4) ); create table test2 ( key1 varchar(8) not null, key2 varchar(4) not null, key3 varchar(6) not null, key4 varchar(11) not null, suryo int(9), kingaku int(11), constraint test2_key primary key (key1,key2,key3,key4) ); 10万件のtest1テーブルに 5件のtest2テーブルの内容をキー集計した結果を test1に反映するにはどうのようなSQL文を書けば、効率的なのでしょうか? 片方のテーブルはデータ量が多く、もう片方は数件の更新処理となります。 宜しくお願いいたします。 ・処理前 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",5,5000 "20070521","3333","333333","33333333333",1, 100 (test2テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","2222","222222","22222222222",10,30000 ↓ ・処理後 (test1テーブル) key1,key2,key3,key4,suryo,kingaku "20070521","1111","111111","11111111111",10,1000 "20070521","2222","222222","22222222222",15,35000 "20070521","3333","333333","33333333333",1, 100

    • ベストアンサー
    • MySQL
  • usersテーブルの構成カラムについて

    MySQLバージョン4.1.16を使用しています。 このジャンルでお願いします。 よく全ての基本となるusersテーブル(IDとパスワードを入れるユーザの基本テーブル) があると思うのですが、それを構成するカラムはどのような感じにするのが良いのでしょうか? 自分は、 CREATE TABLE `users` ( `user_id` varchar(16), `password` varchar(255) default NULL, `col1` varchar(255) NOT NULL, `col2` varchar(255) NOT NULL, PRIMARY KEY (`user_id`), ) ENGINE=InnoDB; このように代替キー(連番)を使わずにuser_idを主キー(unique)にして構成します。 理由としては、uniqueな列があるなら、わざわざ連番を割り当てる必要もないし、 他のテーブルがuser_idを外部キーとして持った時に、その表の外部キーの列が 数字であるよりも見やすいかなと思ったからです。 ただ一般的に出まわっているPHPフレームワークなどのテーブル構成ではusersテーブルというか ほとんどのテーブルに連番を使っている例があります。 次のusersテーブルは、PHPフレームワークのCakePHPで使われるusersテーブルの構成の例で、 連番を使用しています。 CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `username` varchar(255) collate utf8_unicode_ci default NULL, `password` varchar(255) collate utf8_unicode_ci default NULL, `group_id` int(11) NOT NULL, `disabled` tinyint(1) NOT NULL, `created` datetime default NULL, `modified` datetime default NULL, PRIMARY KEY (`id`), KEY `group_id` (`group_id`), KEY `disabled` (`disabled`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 使用状況によって、どちらが良い悪いというのは変わるのでしょうけど 基本的にusersテーブルというのはどのような構成にすべきなのでしょうか? ちなみに自分は連番は○○_seqというカラム名にしてます(ただこれも 一般的には○○idを連番にしてるケースが多いので、どうすべきか迷っています・・・)

    • ベストアンサー
    • MySQL
  • 2つの関連するテーブルで指定した値を条件に取得したい

    mysql5.1.33を使用しています。 次のような構成で、 テーブル「tbl1s」 id int(11) テーブル「tbl2s」 id int(11) name varchar(30) テーブル「tbl1s_tbl2s」 id int(11) tbl1_id int(11) tbl1sの外部キー tbl2_id int(11) tbl2sの外部キー テーブル「tbl1s」 +------+ |  id  | +------+ |  1  | +------+ |  2  | +------+ |  3  | +------+ テーブル「tbl2s」 +------+-------+ |  id  | name | +------+-------+ |  1  | sato  | +------+-------+ |  2  | suzuki | +------+-------+ |  3  | tanaka | +------+-------+ テーブル「tbl1s_tbl2s」 +------+-------+-------+ |  id  | tbl1_id | tbl2_id | +------+-------+-------+ |  1  | 1    | 1   | +------+-------+------+ |  2  | 1    | 2   | +------+-------+------+ |  3  | 3    | 1   | +------+-------+------+ 「tbl1s」テーブルの行を「tbl2s」テーブルのnameを検索条件にして取得したいのですが どのように記述すれば良いのでしょうか? 例えば「sato」を条件にした場合は、 テーブル「tbl1s」 +------+ |  id  | +------+ |  1  | +------+ |  3  | +------+ を取得したいです。

    • ベストアンサー
    • MySQL
  • 簡単に正規化したい

    プログラム素人です。 初心者なのでこんなテーブルを思いつくのですが、これってカラムをいちいち作らないといけないので後のメンテが大変な気がします CREATE TABLE hoge( id INT PRIMARY KEY, item1 VARCHAR(255), value1 INT, item2 VARCHAR(255), value2 INT, item3 VARCHAR(255), value3 INT ); こんな感じのテーブルにどんどんINSERTしていきたいのです CREATE TABLE hoge( id INT PRIMARY KEY, item VARCHAR(255), value INT ); 聞きたいこと MYSQL側 IDにPRIMARY KEYが付いているのですが2つ同じPRIMARY KEYはINSERTでききませんよね?どうすればいいでしょうか? perl側 IDごとにまとめて取得して配列に入れる方法はありますか? idが1のアイテムを全部取得して配列に入れる方法がわかりません(他にいい方法があったらお願いします) よろしくお願いします

    • ベストアンサー
    • MySQL
  • 階層構造のテーブルの行の取得について

    このジャンルでお願いします。 次のようなテーブルで CREATE TABLE IF NOT EXISTS user ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user (name) VALUES ('user1'); INSERT INTO user (name) VALUES ('user2'); INSERT INTO user (name) VALUES ('user3'); CREATE TABLE IF NOT EXISTS item ( id int(11) NOT NULL AUTO_INCREMENT, parent_id INT, name varchar(32) NOT NULL, FOREIGN KEY (parent_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); INSERT INTO item (parent_id, name) VALUES (null, 'item6'); INSERT INTO item (parent_id, name) VALUES (6, 'item7'); INSERT INTO item (parent_id, name) VALUES (null, 'item8'); CREATE TABLE IF NOT EXISTS user_item ( id int(11) NOT NULL AUTO_INCREMENT, user_id INT, item_id INT, type varchar(16) NOT NULL, PRIMARY KEY(id), FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (item_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user_item (user_id, item_id, type) VALUES (1, 1, 'allow'); INSERT INTO user_item (user_id, item_id, type) VALUES (1, 3, 'deny'); INSERT INTO user_item (user_id, item_id, type) VALUES (1, 7, 'allow'); user_itemのuser_idが1のitemの行を取得したいのですが、 その条件として ・user_itemテーブルのtypeが'allow'のitem_id以下のitemの行 ・ただしtypeが'deny'のitem_id以下の行は除く この例だと、user_itemの INSERT INTO user_item (user_id, item_id, type) VALUES (1, 1, 'allow'); の行によってitemテーブルの INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); が取得候補になりますが、 INSERT INTO user_item (user_id, item_id, type) VALUES (1, 3, 'deny'); によって INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); の行は除かれ、 INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); の行が取得されます。 つまりitemテーブルにおいて上の階層の直近の(user_itemと結合して取得した)typeが 'allow'である場合のみ取得したいのです。 INSERT INTO item (parent_id, name) VALUES (null, 'item1');←取得 INSERT INTO item (parent_id, name) VALUES (1, 'item2');←取得 INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5');←取得 INSERT INTO item (parent_id, name) VALUES (null, 'item6'); INSERT INTO item (parent_id, name) VALUES (6, 'item7');←取得 INSERT INTO item (parent_id, name) VALUES (null, 'item8'); 複雑ではありますが、これはどのようなSQL文にすれば良いのでしょうか?

    • ベストアンサー
    • MySQL
  • 2つのテーブルを連結させる方法

    スケジュール管理のできるWEBアプリケーションを作成しようと考えています。 下記構成において、2つのテーブルを連結させるクエリの書き方について教えて頂きたいです。 よろしくお願いします。 ▼DB内容 CREATE TABLE a ( id int primary key autoincrement, year varchar(4), month varchar(2), day varchar(2) ); CREATE TABLE b ( id int (※aテーブルとidで連結させたい) sche1 varchar(10), sche2 varchar(10), sche3 varchar(10), ) ・a +--+----+-----+---+-----+ | id | year | month | day | week | +--+----+-----+---+-----+ | 1 | 2010 | 11 | 20 | 土 | | 2 | 2010 | 11 | 21 | 日 | | 3 | 2010 | 11 | 22 | 月 | | 4 | 2010 | 11 | 23 | 火 | | 5 | 2010 | 11 | 24 | 水 | | 6 | 2010 | 11 | 25 | 木 | | 7 | 2010 | 11 | 26 | 金 | | 8 | 2010 | 11 | 27 | 土 | | 9 | 2010 | 11 | 28 | 日 | | 10 | 2010 | 11 | 29 | 月 | +--+----+-----+---+-----+ ・b +--+-----+------+ | id | sche1| sche2 | +--+-----+------+ | 1 | 空き | 空き | | 2 | 空き | 空き | | 3 | 仕事 | 空き | | 4 | 仕事 | 空き | | 5 | 仕事 | 空き | | 6 | 仕事 | 空き | | 7 | 仕事 | 空き | | 8 | 空き | 空き | | 9 | 空き | 空き | | 10 | 仕事 | 空き | +--+-----+------+ ▼ページ内容 <ユーザ側>日付選択画面 ・calendar.jsp +----------------------+ | << 2010 11月 >> | 日 月 火 水 木 金 土 | ___ _1 _2 _3 _4 _5 _6 | _7 _8 _9 10 11 12 13 | 14 15 16 17 18 19 20 | 21 22 23 24 25 26 27 | 28 29 30 +----------------------+ <ユーザ側>表示処理画面 ・sche.jsp +----------------------+ |2010 11 23 火 のスケジュール | |sch1 仕事 |sch2 空き | +----------------------+ <管理側>日付選択画面 ・m_calendar.jsp +----------------------+ | << 2010 11月 >> | 日 月 火 水 木 金 土 | ___ _1 _2 _3 _4 _5 _6 | _7 _8 _9 10 11 12 13 | 14 15 16 17 18 19 20 | 21 22 23 24 25 26 27 | 28 29 30 +----------------------+ <管理側>編集処理画面 ・m_sche.jsp +---------------------------+ |2010 11 23 火 のスケジュール | |sche1 | +--+-----+ | | ▼ | 仕事 | ※←プルダウンメニュー | +--+-----+ | |sche2 | +--+----+ | | ▼ | 空き | | +--+----+ | | | [登録ボタン] | +------------------+ ※ユーザ側の閲覧は携帯端末を考えてます。 ※値の保持や呼び出しは全てDBで管理しようと思います。 ※使用しているのはMySQL5.1です。

    • ベストアンサー
    • MySQL
  • 異なる2つのテーブルからIDを抜き出し併記したい

    地域別職業別電話帳を作っています。 テーブルは下記の3つです。 市町村テーブル 01city(a1 INT NOT NULL PRIMARY KEY,a2_pre_id INT,a3_pre_name TEXT,a4_city_id INT,a5_city_name TEXT,a6_city_name_kana TEXT); 職業テーブル 03works(c1 INT NOT NULL PRIMARY KEY,c2_work TEXT,c3_aiu TEXT,c4_aiu_id INT); 会社名テーブル tokyo(company TEXT NOT NULL,zip TEXT,address TEXT,tel text,fax TEXT,freedial TEXT,industryA TEXT,hp TEXT,mail TEXT,comment1 TEXT,coid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,industry1 TEXT,zip_id INT,pre_name TEXT,city_name TEXT,induid INT,cityid INT); 会社名の表示については下記のような表示により、13101(千代田区)の104(ラーメン)屋リストを表示出来るようには設定しました。 (クエリー表示を /13101/104/ で表示出来るように .htaccess で指定しています。) http://127.0.0.1/ccs/result/13101/104/ 次に、これを指定するためには、ユーザーが、千代田区(13101) ラーメン(104) と指定したら、http://127.0.0.1/ccs/result/13101/104/のURLが表示出来ることにすれば完成となりますが、ここで躓いてしまいました。 千代田区の職業別一覧なら SELECT * FROM `01city` WHERE a4_city_id = 13101" で表示可能です。 東京のラーメン屋だけなら、 SELECT * FROM `03works` WHERE c1 = 104" で表示な可能です。 しかし、千代田区のラーメン屋になると、拾ってくるID(a4_city_id、c1)のテーブルがそれぞれ別のテーブル(01city、03works)のため、http://127.0.0.1/ccs/result/13101/104/のように並べて表示させることができません。 join関数は、2つのテーブルにキーとなる同じデータがあって初めて結合が可能ですが、今回の場合は、キーとなる同じデータがありません。 普通にありそうな例なのですが、どうすれば可能でしょうか? 基礎的な部分なのかもしれませんが、どうぞ宜しくお願い致します。

    • ベストアンサー
    • MySQL
  • 2つの関連するテーブルで指定した値を条件orで取得したい

    mysql5.1.33を使用しています。 次のような構成で、 テーブル「tbl1s」 id int(11) テーブル「tbl2s」 id int(11) name varchar(30) テーブル「tbl1s_tbl2s」 id int(11) tbl1_id int(11) tbl1sの外部キー tbl2_id int(11) tbl2sの外部キー テーブル「tbl1s」 +------+-------+ |  id  | club | +------+-------+ |  1  | 野球 | +------+-------+ |  2  | テニス| +------+-------+ |  3  | サッカー| +------+-------+ +------+-------+ テーブル「tbl2s」 +------+-------+ |  id  | name | +------+-------+ |  1  | sato  | +------+-------+ |  2  | suzuki | +------+-------+ |  3  | tanaka | +------+-------+ テーブル「tbl1s_tbl2s」 +------+-------+-------+ |  id  | tbl1_id | tbl2_id | +------+-------+-------+ |  1  | 1    | 1   | +------+-------+------+ |  2  | 1    | 2   | +------+-------+------+ |  3  | 3    | 1   | +------+-------+------+ というテーブル構成で、「tbl1s」テーブルの行を 「tbl1s」のclubかない場合には「tbl2s」のnameを検索条件にして取得したいのですが どのように記述すれば良いのでしょうか? 例えば「テニス」を条件にした場合は、「tbl2s」のnameにはないですが「tbl1s」のclubには合致するのがあるので テーブル「tbl1s」 +------+ |  id  | +------+ |  2  | +------+ を取得したいです。

    • ベストアンサー
    • MySQL