[C#]Entity Frameworkでデータ取得する(select)

C#

今回は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テーブル

idtitleuser_nameabout_textpassword
1タイトル1テスト太郎何かの説明1password1
2タイトル2テスト次郎何かの説明2password2
3タイトル3テスト三郎何かの説明3password3
4タイトル4テスト四郎何かの説明4password4

Messagesテーブル

idboard_iduser_namemessage
12レスポンスユーザ1メッセージ1
21レスポンスユーザ2メッセージ2
33レスポンスユーザ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に修正して解決しました。

github(サンプルコード)

コメント

タイトルとURLをコピーしました