简体   繁体   English

EF5:如何仅返回外键?

[英]EF5: how to return only Foreign Keys?

I'm using EF5 code-first in combination with WCF in an N-Tier application. 我在N层应用程序中将EF5代码优先与WCF结合使用。

I'm asynchronously and incrementally loading related entities between client and server. 我正在异步地和增量地在客户端和服务器之间加载相关实体。 All is working well, but I'd like to do some optimization. 一切运行良好,但是我想做一些优化。

Consider a fictitious entity Car , with a related entity Wheel : 考虑一个虚拟实体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; }
}

And the related DTO: 和相关的DTO:

public class CarDTO
{
    public int Id { get; set; }
    public virtual int CarId { get; set; }
    public virtual List<int> Wheels { get; set; }
}

Note that Wheels is a list of foreign keys in the DTO. 请注意, Wheels是DTO中的外键列表。 I don't need to necessarily transfer every Wheel object through the web service - the client will load it in a later WCF call, if needed. 我不需要通过Web服务传输每个Wheel对象,如果需要,客户端将在以后的WCF调用中加载它。 Right now I'm using AutoMapper to flatten the related entities down into a list of FKs. 现在,我正在使用AutoMapper将相关实体展平到FK列表中。

The trouble with this is that my web service doesn't always need to load the entire Wheel object from the DbContext when retrieving a Car object. 这样做的麻烦在于,在检索Car对象时,我的Web服务并不总是需要从DbContext加载整个Wheel对象。 I don't send them across the web service anyway (unless later asked for them). 无论如何,我不会通过网络服务发送它们(除非稍后要求它们)。 But the queries load the entire wheel object from the database into the web service call, only to be discarded. 但是查询会将整个wheel对象从数据库加载到Web服务调用中,而只是被丢弃。 If there are 100 Wheels per Car , that's a significant amount of unnecessary data flowing between the web service and the database. 如果有100个WheelsCar ,这就是Web服务和数据库之间流动的不必要的数据的显著量。

What I would like to do is change Car to something like this: 我想做的就是将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
}

So when the web service knows that it needs to load all of the Wheels , it can do so by adding .Include(car => car.Wheel) to the query, but normally it simply returns a list of FKs in WheelIDs that can be retrieved later. 因此,当Web服务知道需要加载所有Wheels ,可以通过在查询中添加.Include(car => car.Wheel)来实现,但是通常它只是在WheelIDs中返回一个FK列表,该列表可以稍后检索。

Will EF5 do this easily? EF5可以轻松做到这一点吗? If so, how? 如果是这样,怎么办?

Replace 更换

public virtual List<Wheel> Wheels { get; set; }

with

public virtual ICollection<Wheel> Wheels { get; set; }

This way EntityFramework will understand this as a Lazy-loaded child list and won't populate with values until needed. 这样,EntityFramework会将其理解为延迟加载的子列表,并且直到需要时才填充值。

By using LinqToEntities, you can retrieve only the keys into a new list, like: 通过使用LinqToEntities,您只能将密钥检索到新列表中,例如:

public virtual List<int> WheelIDs
{
   get { return Wheels.Select(_w => _w.Id).ToList(); }
}

This won't load the Wheels list but will return only their ID's for your. 这不会加载Wheels列表,但只会返回您的ID。

Remember that this is just a guess. 请记住,这只是一个猜测。 You're needs might change, you might need to avoid DB hit everytime to check for wheels ID's and all, but this should help you find your way. 您的需求可能会发生变化,您可能需要避免每次遇到DB命中来检查车轮ID和所有车轮ID,但这将有助于您找到路。

EDIT: some code to show better usage of IQueryable here... 编辑:一些代码在此处显示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();
      }
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM