EntityFramework 多対多【C#】
経緯
Entity Frameworkで多対多を扱った記事が少なすぎる気がする。
というかSQLをごりごり書いていた身からすると、かなり扱いづらい。
たとえ記事があっても、Controllerでの記述方法が全然見つからない。
新人の子が多対多でデータを取得するのに一緒につまづくことにした。
つまづきポイント① キーがない
まず、リレーションテーブルには主キーが基本的にない。いや、複合主キー設定するという人もいるだろう。さて、主キーを設定したが、モデルクラスはどうすればいいのだろう。
複合主キーを設定してもしなくても怒られる。
キーの設定はDBに欲しいのではない。C#側に欲しいのだ。
dot Net Core (Entity Frame Core )の多対多リレーションの取得|プログラムメモ
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CategoryMemo>().HasKey(bc => new { bc.MemoId, bc.CategoryId });
}
つまづきポイント② どこ基準でとればいいのかわからない
普通SQLを書く場合
select * from Category c
inner join CategoryMemo cm on cm.category_id = c.id
inner join Memo m on m.id = cm.memo_id
というようにとる(経験上)。
今回の場合のできあがるSQLは下記のようにしてとった。
select * from CategoryMemo cm
inner join Category cm on cm.category_id = c.id
inner join Memo m on m.id = cm.memo_id
中間テーブル基準(Model)で取得している。
違和感。。
取得方法の雰囲気は下記の感じ(うろ覚え)。
_context.CategoryMemo.Include(x => x.Categoty).Include(y => y.Memo).ToListAsync();
ちなみにIncludeはjoinの意味で使うようだ。
つまづきポイント③ どこでなにをキーにして結合しているかわからない
上記で、調子にのって、さらにその先まで取得しようとする。
_context.CategoryMemo.Include(x => x.Categoty).Include(y => y.Memo).ThenInclude(z => z.User)ToListAsync();
MemoIdをキーにして取得しようとしてエラーになる。Userが欲しいのであれば、Memoの中にあるUserIdで連携したい。
解決策
SQLで書こう。
SQLで書く良さは次回に記述。