今回はEntity Frameworkでデータを取得するとき(select)のサンプルです。
外部結合・内部結合などなど。
確認環境
・sqlserver2019(docker)・Azure Functions(.Net Core 2.1)
・NuGetライブラリ
=> Microsoft.EntityFrameworkCore 2.2.6
=> Microsoft.EntityFrameworkCore.Design 2.2.6
=> Microsoft.EntityFrameworkCore.SqlServer 2.2.6
=> Microsoft.Net.Sdk.Functions 1.0.31
データを用意する
データがないと始まらないので、とりあえず下記のようにデータを用意しました。
掲示板のイメージで作ってます。
Boardsテーブル
id | title | user_name | about_text | password |
---|---|---|---|---|
1 | タイトル1 | テスト太郎 | 何かの説明1 | password1 |
2 | タイトル2 | テスト次郎 | 何かの説明2 | password2 |
3 | タイトル3 | テスト三郎 | 何かの説明3 | password3 |
4 | タイトル4 | テスト四郎 | 何かの説明4 | password4 |
Messagesテーブル
id | board_id | user_name | message |
---|---|---|---|
1 | 2 | レスポンスユーザ1 | メッセージ1 |
2 | 1 | レスポンスユーザ2 | メッセージ2 |
3 | 3 | レスポンスユーザ3 | メッセージ3 |
DbContextを作る
前回作ったコンテキストにCreateDbContextメソッドを作成して、
コネクションを張ってアクセスするオブジェクトを返してくれるようにしています。
公式のドキュメントをみると、OnConfiguringでもできるように書いてたけど・・・
うまくいかず・・・、良い方法があればコメントください。。
public DBContext CreateDbContext()
{
var optionsBuilder = new DbContextOptionsBuilder<DBContext>();
optionsBuilder.UseSqlServer("server=localhost,1433;database=test01;uid=sa;pwd=yourStrong(!)Password;");
return new DBContext(optionsBuilder.Options);
}
あとは使うところで、usingでnewしてやりたい処理を書いていきます。
using (var _dbContext = new DBContextFactory().CreateDbContext())
{
・・・・ 接続してゴニョゴニョする処理 ・・・・
}
検索(Select)してみる
主キーでSelectする
Findメソッドにキーを渡してあげると取れます。
キーの型がモデルとそろってないとエラーになりました。
var board = _dbContext.Boards.Find((long)2);
結果:
Board Table[ Id:2 Title:タイトル2 UserName:テスト次郎 AboutText:何かの説明2 ]
リストを取得する
LinqのToListメソッドを呼ぶと一括で取れます。
System.Linqをusingしておかないといけないので注意。
var boards = _dbContext.Boards.ToList();
foreach (var row in boards)
{
・・・・ 出力処理 ・・・・
}
結果:
Board Table[ Id:1 Title:タイトル1 UserName:テスト太郎 AboutText:何かの説明1 ]
Board Table[ Id:2 Title:タイトル2 UserName:テスト次郎 AboutText:何かの説明2 ]
Board Table[ Id:3 Title:タイトル3 UserName:テスト三郎 AboutText:何かの説明3 ]
Board Table[ Id:4 Title:タイトル4 UserName:テスト四郎 AboutText:何かの説明4 ]
条件を足して、Selectする
Whereメソッドで条件を書いて、取得します。
複数書く時はメソッドチェイン方式でドットでつないで行けばOKです。
Containsで含む物を探せて、Like検索みたいな感じで使えます。
board = _dbContext.Boards
.Where(e => e.AboutText.Contains("説明3"))
.FirstOrDefault();
結果:
Board Table[ Id:3 Title:タイトル3 UserName:テスト三郎 AboutText:何かの説明3 ]
外部結合する
GroupJoinメソッドを使うと外部結合で取得できます。
2つ目の引数に結合元テーブルのキーと3つ目に結合先テーブルのキーを書きます。
それぞれのテーブルを4つ目の引数に渡して、newでオブジェクトを作ります。
返すオブジェクトの名前をBoard, Messageとしていますが、名前はなんでも大丈夫です。
var leftJoinObjects =_dbContext.Boards
.GroupJoin(_dbContext.Messages,
b => b.Id,
m => m.BoardId,
(joinBoard, joinMessage) => new
{
Board = joinBoard,
Message = joinMessage
}
);
BoardsのId:4のデータに紐づく、Messagesテーブルがないですが、
外部結合なのでId:4のデータが取れてきます!
結果(ループで回して確認してます):
Board Table[ Id:1 Title:タイトル1 UserName:テスト太郎 AboutText:何かの説明1 ]
Message Table[ Id:2 BoardId:1 UserName:レスポンスユーザ2 MessageText:メッセージ2 ]
Board Table[ Id:2 Title:タイトル2 UserName:テスト次郎 AboutText:何かの説明2 ]
Message Table[ Id:1 BoardId:2 UserName:レスポンスユーザ1 MessageText:メッセージ1 ]
Board Table[ Id:3 Title:タイトル3 UserName:テスト三郎 AboutText:何かの説明3 ]
Message Table[ Id:3 BoardId:3 UserName:レスポンスユーザ3 MessageText:メッセージ3 ]
Board Table[ Id:4 Title:タイトル4 UserName:テスト四郎 AboutText:何かの説明4 ]
内部結合する
Joinメソッドを使うと内部結合で取得できます。
GroupJoinの時と同じように渡して、返すデータもnewのところに書きます。
var joinObjects = _dbContext.Boards
.Join(_dbContext.Messages,
b => b.Id,
m => m.BoardId,
(joinBoard, joinMessage) => new
{
Board = joinBoard,
Message = joinMessage
}
);
LeftJoinと比べると、BoardsのId:4のデータに紐づく、Messagesテーブルがないので取れていないですね。
結果(ループで回して確認してます):
Board Table[ Id:2 Title:タイトル2 UserName:テスト次郎 AboutText:何かの説明2 ]
Message Table[ Id:1 BoardId:2 UserName:レスポンスユーザ1 MessageText:メッセージ1 ]
Board Table[ Id:1 Title:タイトル1 UserName:テスト太郎 AboutText:何かの説明1 ]
Message Table[ Id:2 BoardId:1 UserName:レスポンスユーザ2 MessageText:メッセージ2 ]
Board Table[ Id:3 Title:タイトル3 UserName:テスト三郎 AboutText:何かの説明3 ]
Message Table[ Id:3 BoardId:3 UserName:レスポンスユーザ3 MessageText:メッセージ3 ]
エラーが発生
下記のような、何かよくわからないエラーが発生しました。
ILoggerが悪いのかと思いきや、EntityFrameworkのバージョンが高すぎてよくなかったようでした。
Microsoft.Azure.WebJobs.Host: Error indexing method 'xxx'.
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger.
Make sure the parameter Type is supported by the binding.
.NetCore2.1でやってるからかもしれません🤔
3.1.1から2.2.6に修正して解決しました。
コメント