我想选择所有餐馆,并为每家餐馆加载所附类别的列表。
Restaurant
和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; }
}
在我目前的实施中,我选择了包含所有餐馆和类别的原始数据,并在客户端处理它们:按餐厅分组并选择类别。在这种情况下,生成的SQL看起来非常简单并且执行速度很快:
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()
});
另一种变体是使用实体框架以及餐馆和类别之间的关系。在这种情况下,生成的SQL非常复杂,执行速度慢四倍:
var restaurants =(
from restaurant in RestaurantsRepository.GetAll()
select new RestaurantModel
{
Id = restaurant.Id,
Name = restaurant.Name,
Categories = restaurant.Categories
}).ToList();
问题是:有更有效的方法(然后是1或2)来选择我的数据吗?
答案 0 :(得分:1)
您的收藏集是virtual
,因此,我想,您正在使用延迟加载
第二个变体执行N + 1个查询,其中N是项目计数,从RestaurantsRepository.GetAll()
返回:一个查询获取所有餐馆,N个查询获取特定餐厅的所有类别。
尝试使用急切的集合加载:
RestaurantsRepository
.GetAll()
.Include(r => r.Categories)
这应该对数据库执行JOIN
的单一查询,就像这样(真正的SQL会有所不同):
SELECT
*
FROM
[Restaurants] JOIN [Categories] ON [Restaurants].Id = [Categories].[RestaurantId]
另外,考虑延迟加载 - 如果您将查询结果映射到其他类型(样本中为RestaurantModel
),您真的需要它吗?