我在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列表。
这样做的问题是我的Web服务并不总是需要在检索DbContext
对象时从Car
加载整个Wheel对象。我无论如何都不会通过网络服务发送它们(除非后来要求它们)。但是查询将整个wheel对象从数据库加载到Web服务调用中,只是被丢弃。如果每Wheels
有100 Car
,则表示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)
来实现,但通常只需返回{{{{}}中的FK列表1}}可以在以后检索。
EF5会轻易做到这一点吗?如果是这样,怎么样?
答案 0 :(得分:0)
替换
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。
请记住,这只是猜测。 您的需求可能会发生变化,您可能需要每次都避免DB命中以检查车轮ID和所有,但这应该可以帮助您找到自己的方式。
{
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();
}
}
}