LINQ to Entities无法识别方法:LastOrDefault。

12

概述: 在CompletedQuestions表中,UserId对应完成该问题的用户。Id属性对应于Questions表中的一个问题。我知道,我没有正确指定关系。但我经验不太丰富。我只想完成一个项目,等我学到更多的时候就会回来修复这些糟糕的编码实践。我无法理解以下异常。

LINQ to Entities does not recognize the method 'Riddle.Models.CompletedQuestion LastOrDefault[CompletedQuestion](System.Linq.IQueryable`1[Riddle.Models.CompletedQuestion])' method, and this method cannot be translated into a store expression.

    Line 46:                 if (RiddleCompleted == null)
    Line 47:                 {
    Line 48:                     var lastCompletedQuestion = _db.CompletedQuestions.Where(q => q.UserId == currentUserId) // exception occurs in this line
    Line 49:                                                                              .OrderBy(q => q.QuestionNumber)
    Line 50:                                                                              .LastOrDefault();
发生异常的操作:
public ActionResult Riddle(int Id)
        {
            string currentUserId = User.Identity.GetUserId();
            var riddle = _db.Riddles.Where(r => r.Id == Id).Single();

            if (riddle.User.Id == User.Identity.GetUserId())
            {
                var question = riddle.Questions.Where(q => q.QuestionNumber == 1).SingleOrDefault();
                if (question == null)
                {
                    return View("NoMoreQuestions");
                }
                return View("RiddleOwner", question);
            }
            else
            {

                var RiddleCompleted = _db.CompletedRiddles.Where(r => r.Id == Id && r.UserId == currentUserId).SingleOrDefault();
                if (RiddleCompleted == null)
                {
                    var lastCompletedQuestion = _db.CompletedQuestions.Where(q => q.UserId == currentUserId)  // exception occurs in this line
                                                                             .OrderBy(q => q.QuestionNumber)
                                                                             .LastOrDefault();
                    if (lastCompletedQuestion == null)
                    {
                        var question = riddle.Questions.Where(q => q.QuestionNumber == 1).Single();
                        return View(question);
                    }

                    else
                    {
                        var question = riddle.Questions.Where(q => q.QuestionNumber == lastCompletedQuestion.QuestionNumber + 1).SingleOrDefault();
                        return View(question);
                    }
                }
                else
                {
                    return View("NoMoreQuestions");
                }
            }
        }

已完成的问题模型:

public class CompletedQuestion
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public int QuestionNumber { get; set; }
}

问题模型:

  public class Question
    {
        public int Id { get; set; }
        public string Body { get; set; }
        public string Answer { get; set; }
        public Riddle Riddle { get; set; }
        [Column(TypeName ="datetime2")]
        public DateTime CreationDate { get; set; }
        public int QuestionNumber { get; set; }
    }
2个回答

33

LastOrDefault()在Linq To Entities中不受支持。因此,它只能在内存中处理集合,而不能在尝试查询数据库时使用。

以下是一个有效的处理方法:

var lastCompletedQuestion = 
_db.CompletedQuestions.Where(q => q.UserId == currentUserId)
.OrderByDescending(q => q.QuestionNumber)
.FirstOrDefault() 

                                                                         ;

4

Entity framework/linq2sql 的工作原理是将编译后的C#/IL代码转化为SQL。它只能转化已知的方法。错误提示说明 LastOrDefault 不在已知方法之列。

您可以通过在 LastOrDefault 前加上 .ToList() 来解决这个问题,这样它就不再是 SQL 转换器而是普通的 C# 代码了,您就可以得到正常的 LastOrDefault 版本。或者您可以反过来使用 FirstOrDefault,因为它是可以被转换的。


我只想强调一下,即使将其转换为列表,然后使用 LastOrDefault 也无法解决我的问题,翻转列表然后使用 FirstOrDefault 也不行,但知道 LINQ to Entities 不支持这些函数还是很好的。 - Somu
这个方法可以运行,但是需要小心,因为 .ToList() 会在从内存中选择第一个实体之前,将所有实体从数据存储中加载。如果您想继续处理列表中的其他项,最好不要使用该方法。 - Chad McGrath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接