0

我在 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 中的外键列表。我不需要Wheel通过 Web 服务传输每个对象 - 如果需要,客户端将在稍后的 WCF 调用中加载它。现在我正在使用 AutoMapper 将相关实体扁平化为 FK 列表。

DbContext这样做的问题是,我的 Web 服务在检索对象时并不总是需要加载整个 WheelCar对象。无论如何,我不会通过 Web 服务发送它们(除非后来要求它们)。但是查询将整个 wheel 对象从数据库加载到 Web 服务调用中,然后被丢弃。如果有 100 个Wheelsper 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)所有WheelIDs.

EF5 会轻松做到这一点吗?如果是这样,怎么做?

4

1 回答 1

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

这不会加载 Wheels 列表,但只会为您返回他们的 ID。

请记住,这只是一个猜测。您的需求可能会发生变化,您可能需要每次都避免 DB 命中以检查车轮 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();
      }
   }
}
于 2013-09-27T00:30:03.647 回答