C# EntityFrameworkでネストしたプロパティのデータを取得する
概要
タイトルですでに何言ってるかわからないですよね。自分でも表現の仕方がわからないです。
SQLで言うとLEFT JOINをネスト(LEFT JOINの中にLEFT JOIN)させてデータを取得する感じです。
それをLINQ to Entitiesでやりたかった。できたのでメモ
SELECT 適当 FROM 適当A AS A LEFT JOIN ( SELECT * FROM 適当B LEFT JOIN (SELECT * FROM 適当C) AS C ON 適当 ) AS B ON 適当
目次
環境
- Windows 10 Pro (バージョン:1709)
- Visual Studio Community 2015 Update3
- Microsoft SQL Server Express
- .NET Framework 4.6
- EntityFramework 6.2
ソース
登場人物(オブジェクト)
最初にDBのリレーション(ER図)を見せておきます。テーブルの全体像です。
護衛艦テーブル
class SelfDefenseShip { //護衛艦 public virtual EscortDivision EscortDivision { get; set; } //所属 public virtual HullCode HullCode { get; set; } //艦種記号 [Key] public int ShipNumber { get; set; } //艦識別番号 public string ShipName { get; set; } //艦名 public virtual ShipClass ShipClass { get; set; } //艦種型 public int StandardDisplacement { get; set; } //基準排水量(トン) public int FullLoadDisplacement { get; set; } //満載排水量(トン) public double FullLength { get; set; } //全長(メートル) public double FullWidth { get; set; } //全幅(メートル) public DateTime CommissionYear { get; set; } //就役(年) }
隊テーブル
class EscortDivision { //護衛隊 [Key] public int EscortDivisionId { get; set; } //護衛隊ID public string EscortDivisionName { get; set; } //護衛隊名 ex.第1護衛隊 public virtual EscortFlotilla EscortFlotilla { get; set; } //所属護衛隊群 public virtual ICollection<SelfDefenseShip> SelfDefenseShips { get; set; } //所属艦艇 }
群テーブル
class EscortFlotilla { //護衛隊群 [Key] public int EscortFlotillaId { get; set; } //護衛隊群ID public string EscortFlotillaName { get; set; } //護衛隊群名 ex.第1護衛隊群 public virtual ICollection<EscortDivision> EscortDivision { get; set; } }
艦種テーブル
class HullCode { //艦種別 [Key] public int HullCodeId { get; set; } //艦種記号ID public string HullCodeSymbol { get; set; } //艦種記号 ex.DD,DDG,DDH public virtual ICollection<SelfDefenseShip> SelfDefenseShips { get; set; } //種別護衛艦 }
抽出目的のデータ(目指すべき姿)
言葉で表せば隊テーブルを元に隊が所属している上位組織である所属群のデータを取得し、さらに隊に所属する艦船のデータを取得します。
SQLで表すとこんな感じです。
SELECT Flotillas.EscortFlotillaName AS 所属護衛隊群 , Divisions.EscortDivisionName AS 所属護衛隊 , Ships.HullCodeSymbol AS 艦種記号 , Ships.ShipNumber AS 艦船番号 , Ships.ShipName AS 艦船名 FROM EscortDivisions AS Divisions LEFT JOIN (SELECT * FROM EscortFlotillas) AS Flotillas ON Divisions.EscortFlotilla_EscortFlotillaId = Flotillas.EscortFlotillaId LEFT JOIN ( SELECT * FROM SelfDefenseShips LEFT JOIN (SELECT * FROM HullCodes) AS Code ON HullCode_HullCodeId = Code.HullCodeId ) AS Ships ON Divisions.EscortDivisionId = Ships.EscortDivision_EscortDivisionId ORDER BY Flotillas.EscortFlotillaId , Divisions.EscortDivisionId , Ships.ShipNumber
こんな感じのデータが欲しいのです。
LINQ to Entitiesでデータを抽出
抽出でき”ない”コード
下記のコードだとInclude
で艦船情報(SelfDefenseShip
)に紐付いているデータが全て抽出されているイメージでしたが艦種コード(HullCode
)まで読み込まれていませんでした。
.Include(x => x.SelfDefenseShips)
で更に続けてHullCode
を読み込もうとしてましたが候補に表示されませんし、奇妙な書き方をするとエラーで怒られます。
残念!
class ReadDataStore { public ICollection<EscortDivision> ReadDivisionAllData() { using (var db = new ShipsDbContext()) { db.Database.Log = sql => { Debug.Write(sql); }; var dd = db.EscortDivisions.Include(x => x.EscortFlotilla) .Include(x => x.SelfDefenseShips) .ToList(); return dd; } } }
抽出できるコード
件のコードです。これで出来ました。
読み込んだSelfDefenseShip
テーブルに対して個別にSelect
で読みこむプロパティを指定する必要がありました。
class ReadDataStore { public ICollection<EscortDivision> ReadDivisionAllData() { using (var db = new ShipsDbContext()) { var dd = db.EscortDivisions.Include(x => x.EscortFlotilla) .Include(x => x.SelfDefenseShips .Select(y => y.HullCode)) .ToList(); return dd; } } }
ちゃんとデータが出力されました!
参考サイト様
雑感
GW前半戦の宿題を消化出来てよかったです。