[英]LINQ statement for joining multiple tables (Entity Framework 6)
我是LINQ / Entity Framework的新手,我在努力如何聯接表。
我有以下課程:
public class PhotoPlace
{
#region attributes
[Key]
public long Id { get; set; }
public List<ParkingLocation> ParkingLocations { get; set; }
public SubjectLocation PlaceSubjectLocation { get; set; }
#endregion
#region constructors
public PhotoPlace()
{
}
#endregion
}
public class ParkingLocation : LocationBase
{
#region attributes
public PhotoPlace PhotoPlace { get; set; }
public List<ShootingLocation> ShootingLocations { get; set; }
#endregion
public ParkingLocation()
{
}
}
public class ShootingLocation : LocationBase
{
#region attributes
public ParkingLocation ParkingLocation { get; set; }
public List<Photo> Photos { get; set; }
#endregion
#region constructors
public ShootingLocation()
{
}
#endregion
}
public class Photo
{
#region attributes
public long Id { get; set; }
public byte[] ImageBytes { get; set; }
public ShootingLocation ShootingLocation { get; set; }
#endregion
#region constructors
public Photo()
{
}
#endregion
}
因此,一個PhotoPlace具有多個ParkingLocations ,一個ParkingLocation具有多個ShootingLocations ,一個ShootingLocation具有多個Photos 。
現在,我想讀取包含所有相關對象的PhotoPlace:在添加照片之前,使用以下語句一切都很好:
using (var db = new LocationScoutContext())
{
photoPlacesFound = db.PhotoPlaces.Include(pp => pp.PlaceSubjectLocation)
.Include(pp => pp.ParkingLocations.Select(pl => pl.ShootingLocations))
.Include(pp => pp.PlaceSubjectLocation.SubjectCountry)
.Include(pp => pp.PlaceSubjectLocation.SubjectArea)
.Include(pp => pp.PlaceSubjectLocation.SubjectSubArea).ToList();
}
其他類別應該沒關系。 我試圖延長
.Include(pp => pp.ParkingLocations.Select(pl => pl.ShootingLocations))
帶有另一個“選擇”的語句,但無法解決。 任何幫助都非常歡迎。
使用thenInclude嘗試以下操作
using (var db = new LocationScoutContext())
{
photoPlacesFound = db.PhotoPlaces.Include(pp => pp.ParkingLocations)
.ThenInclude(pp => pp.ShootingLocations)
.ThenInclude(pp => pp.Photos)
.ToList();
}
數據庫查詢的最慢部分之一是將選定的數據從數據庫管理查詢傳輸到本地進程。 因此,僅選擇您實際打算使用的值是明智的。
例如,每個PhotoPlace
都有零個或多個ParkingLocations
,每個ParkingLocaction
使用外鍵恰好屬於一個PhotoPlace
。 一個相當簡單的一對多關系。
因此,如果PhotoPlace 4具有1000個ParkingLocations,則每個ParkingLocation都將有一個外鍵指向它所屬的PhotoPlace。 如預期的那樣,此外鍵的值為4。
當使用“ Include
來獲取帶有其ParkingLocations的PhotoPlace時,您還選擇了外鍵。 發送1000倍的值4是多么浪費,而您已經知道此值。
使用實體框架時,請始終使用“選擇”而不是“包含”。 僅當計划更新獲取的數據時才使用包括。
以下查詢將更加高效,因為它僅選擇您實際計划使用的屬性:
var photoPlacesFound = db.PhotoPlaces
.Where(photoPlace => ...) // if you don't want all PhotoPlaces
.Select(photoPlace => new
{
// Select only the PhotoPlace properties you actually plan to use:
Id = photoPlace.Id,
...
ParkingLocations = PhotoPlace.ParkingLocations
.Select(parkingLocation => new
{
// again: select only the ParkingLocation properties you plan to use
Id = parkingLocation.Id,
Name = parkingLocation.Name,
// not needed: you already know the value:
// PhotoPlaceId = parkingLocation.PhotoPlaceId, // foreign key
ShootingLocations = parkingLocations.ShootingLocations
.Select(shootingLocation => new
{
// you know the drill by now: only select the ...
})
.ToList(),
})
.ToList(),
});
一些改進
我注意到您已將一對多關系聲明為列表而不是ICollection。 您確定PhotoPlace.ParkingLocation [4]具有適當的含義嗎?
我還注意到您沒有聲明表之間的關系是虛擬的
在實體框架中,非虛擬屬性表示表的列。 表之間的關系(一對多,多對多...)由虛擬屬性表示。
只要遵循實體框架代碼優先約定 ,大多數元素就不需要屬性或流暢的API,從而使代碼更緊湊,更易於閱讀:
public class PhotoPlace
{
public long Id { get; set; }
... // other properties
// every PhotoPlace has zero or more ParkingLocations (one-to-many)
public virtual ICollection<ParkingLocation> ParkingLocations { get; set; }
}
public class ParkingLocation
{
public long Id {get; set;}
...
// every ParkingLocation belongs to exactly one PhotoPlace using foreign key
public long PhotoPlaceId {get; set;}
public virtual PhotoPlace PhotoPlace {get; set;}
// every ParkingLocation has zero or more ShootingLocations (one-to-many)
public virtual ICollection<ShootingLocation> ShootingLocations {get; set;}
}
因為我遵循了約定,所以ModelBuilder能夠檢測表和列的名稱。 它可以檢測主鍵。 由於存在虛擬關鍵字,因此它知道表與這些關系中使用的外鍵之間的關系。
因為我使用ICollection <...>,所以您的編譯器不會接受未定義的功能,例如List [4]
最后:由於構造函數不執行任何操作,因此我將其刪除
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.