概要
タイトルですでに何言ってるかわからないですよね。自分でも表現の仕方がわからないです。
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
ソース
https://github.com/Lycheejam/EntityFramework_Sample 🔗
登場人物(オブジェクト)
最初に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前半戦の宿題を消化出来てよかったです。