みなさんこんにちは!ひろぽんです!!
今回はAsp.netのModel参照でデータを取得する場合に避けて通れないInclude関数で盛大な勘違いをしていたことについて書いていきたいと思います。
発端はModel参照がNullになっていたこと
namespace IncludeStudy.Models
{
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
public Company(int id, string name)
{
Id = id;
Name = name;
}
public Company()
{
}
}
}
こんな感じのモデルがあって、下記のようなControllerがあります。
(Controllerは基本スキャフォールドしてるものなので、抜粋しています。)
// GET: api/Companies/5
[HttpGet("{id}/emp")]
public async Task<ActionResult<ICollection<Employee>>> GetCompanyEmp(int id)
{
var company = await _context.Company.FindAsync(id);
if (company == null)
{
return NotFound();
}
return company.Employees.ToList();
}
で、このURLをたたいて中身を見ると下記のようになってます。
せっかくModel参照しているのにデータがNullになっています。
なので公式リファレンスを見たところIncludeを使え!と書いていました。
https://docs.microsoft.com/ja-jp/ef/core/querying/related-data/eager
Include関数は戻り値があると思っていた。
でここからが盛大な勘違い。
ICollection<Employee> emps = _context.Company.Include(com => com.Employees).ToList();
Include関数はLinqみたいにラムダ式を使うので、Linqのように値が返ってくると思っていました。
でもこれだとコンパイルエラーが出ます。
データ型が違うとのこと。
Includeを使っても戻り値は_context.CompanyならCompanyでしかありません。
で、思ったのがIncludeってなんやねんって事。
IncludeはSqlでいうところのJoinをして返してくれる
その後Includeについていろいろ調べていました。
結果わかったことはInclude関数はSqlでいうところのJoinをした結果を全て返してくれるものということが分かりました。
どういうことかというと、下記のプログラムで取得したデータ
var company = await _context.Company.FindAsync(id);
これは、Sqlに直すと下記のようになります。
select * from Company where id = @id
これだとModel参照で取得しようとしているEmployeeのテーブルのデータが取れずにNullになってしまいます。
一方でIncludeを使ってCompanyを取得すると下記のようになります。
var company = await _context.Company.Include(com => com.Employees).FirstOrDefault(com => com.Id == id);
これだとSqlに直すとこんな感じ
select *
from Company as a
inner join Employees as b
on(a.EmployeeId = b.Id)
where a.Id = @id
こんな感じになるので、あくまでも戻り値はCompanyなのですが、Companyの中にはEmployeeが入っているということになります。
値が入っていますね!
まとめ
今回ThenIncludeの解説を省きましたが、端的に言うとThenIncludeはIncludeで取ったデータのその先のデータを取得できるというものになります。
まあおそらくIncludeについての動きが分かった状態で下記の公式リファレンスを見れば、何をどのようにすれば目的のデータが取れるかはわかると思います!
https://docs.microsoft.com/ja-jp/ef/core/querying/related-data/
今回のソースコードはGithubに上げています!
今回のソースコードは下記リポジトリの中にAspnet=>IncludeDemoという形で置いています!
ご自由にお使いください!
コメント