Получение первого результата из запроса LINQ - почему ElementAt <T>(0) завершается ошибкой, когда First <T>() завершается успешно? - PullRequest
3 голосов
/ 16 апреля 2010

У меня есть метод AddStudent () , который ищет студента с таким же именем и возвращает существующего студента из базы данных, если есть студент с таким же именем, в противном случае он создает нового студента и добавляет его в базу данных.

Мне любопытно, почему se = students.First<StudentEntity>(); удается, когда se = students.ElementAt<StudentEntity>(0); не удается, когда я пытаюсь получить первый результат из запроса LINQ. Разве эти два метода не одинаковы?

Полный код метода показан ниже.

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);
    }
}

Спасибо!

1 Ответ

8 голосов
/ 16 апреля 2010

Сбой, потому что метод ElementAt является методом индексированного доступа, а Entity Framework не знает, как превратить его в SQL.

Когда вы используете метод First, Entity Framework может преобразовать это в предложение TOP 1 в запросе SQL. Это очень очень просто. Чтобы использовать ElementAt, он должен был бы построить гораздо более сложный запрос, основанный на оконных функциях (ROW_NUMBER()), и, ну, он просто не достаточно сложен, чтобы сделать это.

Это на самом деле задокументированное ограничение Entity Framework. Расширение ElementAt просто не поддерживается.


Теоретически вы могли бы написать это вместо:

se = students.AsEnumerable().ElementAt<StudentEntity>(0);

Это дает указание Entity Framework не пытаться «переводить» что-либо после вызова AsEnumerable(), поэтому вместо этого он извлекает всех результатов (не только первых) и выполняет итерацию по ним до он попадает к элементу, который вы хотите (который в данном случае просто бывает первым).

Однако это замедлит работу на по сравнению с использованием First(), потому что вместо того, чтобы просто получать 1 результат с сервера, он выбирает их все и фильтрует впоследствии. Я бы использовал этот обходной путь, только если по какой-то странной причине мне нужно было получить 5-й или 10-й элемент или какой-то элемент , отличный , чем первый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...