[英]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.