获取List <class>表单</class>中的子集合

时间:2010-09-16 19:44:26

标签: c# linq-to-entities

我有一个LINQ to EF查询,它以类的形式返回数据。该类具有我需要填充的List<RecipeCategories>属性。 RecipeCategories表是Recipe表和RecipeCategories表之间的关系表,可以是多对多。我找到了足够的信息来编译代码,但是在运行时它出错并且我无法弄清楚如何做到这一点。

ri = (from r in recipeData.Recipes
              where r.ID == recipeId
              select new RecipeItem
              {
                  Id = r.ID,
                  ProductId = r.Product.ID,
                  RecipeName = r.recipeName,
                  RecipeDescription = r.recipeDescription,
                  Servings = r.servings.HasValue ? r.servings.Value : 0,
                  CreatedDate = r.createdDate,
                  PrepTime = r.prepTime.HasValue ? r.servings.Value : 0,
                  CookTime = r.cookTime.HasValue ? r.servings.Value : 0,
                  Approved = r.approved,
                  RecipeInstructions = r.recipeInstructions,
                  RecipeIngredients = r.recipeIngredients,
                  RecipeCategories = r.RecipeCategories.Select(i => new RecipeCategoryItem { Id = i.ID, CategoryName = i.categoryName }).ToList()
              }).First();

这是我得到的错误。

  

LINQ to Entities无法识别方法'System.Collections.Generic.List 1[RecipeCategoryItem] ToList[RecipeCategoryItem](System.Collections.Generic.IEnumerable 1 [RecipeCategoryItem])'方法,并且此方法无法转换为商店表达式。

我正在处理的部分是这一行。

RecipeCategories = r.RecipeCategories.Select(i => new RecipeCategoryItem { Id = i.ID, CategoryName = i.categoryName }).ToList()

RecipeCategories是List<RecipeCategoryItem>属性。

我正在尝试做什么,如果是,怎么做?

谢谢。

3 个答案:

答案 0 :(得分:11)

你正在调用ToList内部变成一个更大的查询。删除对.ToList()的调用。

问题是查询中的所有内容都变成了一个大的表达式树,实体框架试图将其转换为SQL语句。从“SQL”的角度来看,“ToList”没有任何意义,所以你不应该在里面的任何地方调用它。

在大多数情况下,您希望在返回整个查询之前调用ToList,以确保评估查询并将结果加载到内存中。在这种情况下,您只返回一个对象,因此对First的调用基本上是相同的。

RecipeCategories对List<RecipeCategoryItem>有多重要?如果您可以改为IEnumerable,那么您可以毫无问题地删除对ToList的调用。

如果您必须拥有List,那么首先需要使用初始实体框架查询和匿名类型(不调用ToList)获取所有信息,然后转换您收到的数据在返回之前进入你想要的对象类型。

或者您可以从多个查询中逐步构建RecipeInfo对象,如下所示:

var ri = (from r in recipeData.Recipes
            where r.ID == recipeId
            select new RecipeItem
            {
                Id = r.ID,
                ProductId = r.Product.ID,
                RecipeName = r.recipeName,
                RecipeDescription = r.recipeDescription,
                Servings = r.servings.HasValue ? r.servings.Value : 0,
                CreatedDate = r.createdDate,
                PrepTime = r.prepTime.HasValue ? r.servings.Value : 0,
                CookTime = r.cookTime.HasValue ? r.servings.Value : 0,
                Approved = r.approved,
                RecipeInstructions = r.recipeInstructions,
                RecipeIngredients = r.recipeIngredients,
            }).First();
var rc = from c in recipeData.RecipeCategories
         where c.Recipes.Any(r => r.ID == recipeId)
         select new RecipeCategoryItem 
         {
            Id = c.ID, CategoryName = c.categoryName
         };
ri.RecipeCategories = ri.ToList();

请注意,最后一个示例将导致两次数据库跳转,但会导致更少的数据通过线路发送。

答案 1 :(得分:2)

我想我有一个问题的解决方案。使用动态类型。

public class BoxImageViewDetailDto
{
    public Guid PropertyId { get; set; }

    public string Title { get; set; }
    public string SubTitle { get; set; }
    public string Description { get; set; }
    public string SubDescription { get; set; }

    public decimal? PropertyValue { get; set; }
    public byte? UnitsFloor { get; set; }

    public dynamic ImagensRowsVar { get; set; }
    public List<ImageViewDto> ImagensRows 
    {
        get
        {
            return (List<ImageViewDto>)this.ImagensRowsVar; 
        }
    }

    public int ImagensRowsTotal { get; set; }
}

CorretorDaVez.DTO.UserControls.BoxImageViewDetailDto c = (from p in entities.rlt_Property
  join pc in entities.rlt_PropertyPicture on p.PropertyId equals pc.PropertyId
  where p.PropertyId == propertyId
  orderby p.CreateDate descending
  select new CorretorDaVez.DTO.UserControls.BoxImageViewDetailDto
  {
      PropertyId = p.PropertyId,
      Title = p.Title,
      PropertyValue = p.PropertyValue,
      Description = p.Description,
      UnitsFloor = p.UnitsFloor,
      ImagensRowsTotal = p.rlt_PropertyPicture.Count,
      ImagensRowsVar = p.rlt_PropertyPicture.Select(s => new CorretorDaVez.DTO.UserControls.ImageViewDto { PropertyId = p.PropertyId, ImagePath = pc.PhotoUrl})
  }).FirstOrDefault();

答案 2 :(得分:0)

尝试:



    var ri = (from r in recipeData.Recipes
              where r.ID == recipeId
              select new RecipeItem
              {
                  Id = r.ID,
                  ProductId = r.Product.ID,
                  RecipeName = r.recipeName,
                  RecipeDescription = r.recipeDescription,
                  Servings = r.servings.HasValue ? r.servings.Value : 0,
                  CreatedDate = r.createdDate,
                  PrepTime = r.prepTime.HasValue ? r.servings.Value : 0,
                  CookTime = r.cookTime.HasValue ? r.servings.Value : 0,
                  Approved = r.approved,
                  RecipeInstructions = r.recipeInstructions,
                  RecipeIngredients = r.recipeIngredients,
                  RecipeCategories = from rc in recipeData.RecipeCategories
                                     where rc.Recipes.Any(r => r.ID == recipeId)
                                     select new RecipeCategoryItem{
                                              Id = rc.ID, 
                                              CategoryName = rc.categoryName
                                           } 
      ).First();