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 是否可以轻松做到这一点? 如果是这样,如何?

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();
      }
   }
}