I want select the all restaurants, and for the each restaurant load the list of the attached categories.
There is a many-to-many relationship between the Restaurant
and Category
:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Category> Categories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Value { get; set; }
}
In my current implementation I'm selecting a raw data with all restaurants and categories, and process them on the client side: group by restaurant and select categories. In this case, the generated SQL looks very simple and executed fast:
var plainData = (
from restaurant in RestaurantsRepository.GetAll()
from category in restaurant.Categories
select new
{
Id = restaurant.Id,
Name = restaurant.Name,
Category = category.Value
}).ToList();
var restaurants = (
from restaurant in plainData
group restaurant by new
{
restaurant.Id,
restaurant.Name
}
into grp
select new RestaurantModel
{
Id = grp.Key.Id,
Name = grp.Key.Name,
Categories = grp.Select(c => c.Category).ToList()
});
The another variant is to use Entity Framework and the relation between restaurants and categories. In this case, the generated SQL is very complicated and executed four times slower:
var restaurants =(
from restaurant in RestaurantsRepository.GetAll()
select new RestaurantModel
{
Id = restaurant.Id,
Name = restaurant.Name,
Categories = restaurant.Categories
}).ToList();
The question is: There is there a more efficient way (then 1 or 2) to select my data?
Your collection is virtual
, thus, I suppose, you're using lazy loading.
The second variant executes N + 1 queries, where N is a count of items, returned from RestaurantsRepository.GetAll()
: one query to get all restaurants, and N queries to get all categories for the particular restaurant.
Try to use eager loading of collection:
RestaurantsRepository
.GetAll()
.Include(r => r.Categories)
This should execute single query with JOIN
against database, like this (real SQL will differ):
SELECT
*
FROM
[Restaurants] JOIN [Categories] ON [Restaurants].Id = [Categories].[RestaurantId]
Also, think about lazy loading - do you really need it, if you're mapping query result into another types ( RestaurantModel
in your sample).
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.