简体   繁体   中英

EF5: how to return only Foreign Keys?

I'm using EF5 code-first in combination with WCF in an N-Tier application.

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 :

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:

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. 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. Right now I'm using AutoMapper to flatten the related entities down into a list of FKs.

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. 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. If there are 100 Wheels per Car , that's a significant amount of unnecessary data flowing between the web service and the database.

What I would like to do is change Car to something like this:

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.

Will EF5 do this easily? 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.

By using LinqToEntities, you can retrieve only the keys into a new list, like:

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.

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.

EDIT: some code to show better usage of IQueryable here...

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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