从LINQ查询中获取第一个结果 - 当First <T>()成功时,为什么ElementAt <T>(0)会失败?

ano*_*ous 3 c# linq entity-framework

我有一个方法AddStudent(),它查找具有相同名称的学生,如果有同名学生,则从数据库返回现有学生,否则它会创建一个新学生并将其添加到数据库中.

我很好奇为什么当我尝试从LINQ查询获得第一个结果se = students.First<StudentEntity>();se = students.ElementAt<StudentEntity>(0);失败成功.这两种方法不一样吗?

该方法的完整代码如下所示.

public Student AddStudent(string name)
{
    using (SchoolEntities db = new SchoolEntities())
    {
        // find student with same name via LINQ
        var students = from s in db.StudentEntitySet
                       where s.name == name
                       select s;

        StudentEntity se = default(StudentEntity);

        // if student with the same name is already present, return 
        // that student
        if (students.Count<StudentEntity>() > 0)
        {
            // if i use ElementAt, if fails with a "LINQ to Entities does not
            // recognize the method 'StudentEntity ElementAt[StudentEntity]
            // (System.Linq.IQueryable`1[StudentEntity], Int32)' method, 
            // and this method cannot be translated into a store expression.", 
            // but not when I use First. Why?

            // se = students.ElementAt<StudentEntity>(0);
            se = students.First<StudentEntity>();
        }
        else
        {
            // passing 0 for first parameter (id) since it's represented by 
            // a BigInt IDENTITY field in the database so any value
            // doesn't matter.
            se = StudentEntity.CreateStudentEntity(0, name);
            db.AddToStudentEntitySet(se);
            db.SaveChanges();
        }

        // create a Student object from the Entity object
        return new Student(se);
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Aar*_*ght 8

它失败是因为该ElementAt方法是索引访问方法,而实体框架不知道如何将其转换为SQL.

使用该First方法时,Entity Framework可以将其转换TOP 1为SQL查询中的子句.这非常简单.为了使用ElementAt它,它必须构建一个基于窗口函数(ROW_NUMBER())的更复杂的查询,而且,它只是不够复杂到那么做.

它实际上是实体框架的文档限制.该ElementAt扩展名根本不支持.


理论上,你可以这样写:

se = students.AsEnumerable().ElementAt<StudentEntity>(0);
Run Code Online (Sandbox Code Playgroud)

这指示实体框架在AsEnumerable()调用之后不要尝试"翻译"任何内容,因此它将检索所有结果(而不仅仅是第一个)并迭代它们直到它到达您想要的元素(在这种情况下)只是碰巧是第一个).

然而,这会减慢运行了很多比仅仅使用First(),因为不是从服务器获取刚刚1分的结果,它获取所有这些和过滤器之后.如果出于某种奇怪的原因,我需要得到第5或10元或某些元素,我只会使用此解决方案的其他比第一个.