EF5:如何仅返回外键
本文关键字:返回 何仅 EF5 | 更新日期: 2023-09-27 18:33:08
我在 N 层应用程序中将 EF5 代码优先与 WCF 结合使用。
我正在客户端和服务器之间异步和增量加载相关实体。一切正常,但我想做一些优化。
考虑一个虚构的实体Car
,其相关实体Wheel
:
public class Car
{
public int Id { get; set; }
public virtual List<Wheel> Wheels { get; set; }
}
public class Wheel
{
public int Id { get; set; }
public virtual int CarId { get; set; }
}
以及相关的 DTO:
public class CarDTO
{
public int Id { get; set; }
public virtual int CarId { get; set; }
public virtual List<int> Wheels { get; set; }
}
请注意,Wheels
是 DTO 中的外键列表。我不需要通过 Web 服务传输每个Wheel
对象 - 如果需要,客户端将在以后的 WCF 调用中加载它。 现在我正在使用AutoMapper将相关实体扁平化为FK列表。
这样做的问题是,在检索Car
对象时,我的 Web 服务并不总是需要从DbContext
加载整个 Wheel 对象。无论如何,我都不会通过 Web 服务发送它们(除非以后要求它们(。 但是查询将整个轮子对象从数据库加载到 Web 服务调用中,只是被丢弃。如果每个Car
有 100 个Wheels
,那就是在 Web 服务和数据库之间流动的大量不必要的数据。
我想做的是将Car
更改为如下所示:
public class Car
{
public int Id { get; set; }
public virtual List<Wheel> Wheels { get; set; } // Normally empty
public virtual List<int> WheelIDs { get; set; } // Normally full
}
因此,当Web服务知道它需要加载所有Wheels
时,它可以通过向查询添加.Include(car => car.Wheel)
来实现,但通常它只是返回一个可以在以后检索的WheelIDs
FK列表。
EF5 是否可以轻松做到这一点? 如果是这样,如何?
替换
public virtual List<Wheel> Wheels { get; set; }
跟
public virtual ICollection<Wheel> Wheels { get; set; }
这样,EntityFramework 会将其理解为延迟加载的子列表,并且不会在需要时填充值。
通过使用 LinqToEntities,可以仅将键检索到新列表中,例如:
public virtual List<int> WheelIDs
{
get { return Wheels.Select(_w => _w.Id).ToList(); }
}
这不会加载轮子列表,但只会返回它们的 ID。
请记住,这只是一个猜测。您的需求可能会发生变化,您可能需要避免每次都击中数据库以检查车轮 ID 和所有,但这应该可以帮助您找到自己的方式。
编辑:一些代码在这里显示IQueryable的更好用法...
{
using(var context = new MyContext())
{
// Doing this the wheel collection WON'T GET LOADED
var cars = context.Cars;
}
using(var context = new MyContext())
{
// Doing this the wheel collection WILL get loaded
var cars = context.Cars.Include(_c => _c.Wheels);
}
using(var context = new MyContext())
{
// Doing this also gets the wheel collection loaded
// But this time, it will retrieve wheel-by-wheel on each loop.
var cars = context.Cars;
foreach(var car in cars)
{
foreach(var wheel in wheels)
{ /* do something */ }
}
}
using (var context = new MyContext())
{
// Doing this will get your id's without loading the entire wheel collection
var cars = context.Cars;
var wheelsIDs = cars.Wheels.Select(_w => _w.Id).ToList();
}
using (var context = new MyContext())
{
// Doing this will return every wheel for your car.
// This improves performance over the other that retrieves wheel-by-wheel.
var cars = context.Cars;
foreach(var car in cars)
{
var wheels = car.Wheels.ToList();
}
}
}