Свойство Entity Navigation IQueryable нельзя преобразовать в выражение хранилища

Сначала я использую конструктор Entity Framework, и мне нужно создать пользовательские объекты модели, начиная с объектов db. Я не хочу использовать IEnumerable, потому что он будет запрашивать слишком много полей.

Цель состоит в том, чтобы удалить внутренний выбор внутри этой функции:

using (var db = new dbEntities())
{
   var departments= db.departments
                      .Include(p => p.employee)
                      .Where(...)
                      .Select(p => new CustomDepartmentModel()
                      {
                         ID = p.ID,
                         Employees = p.employee
                                .Select(q => new CustomEmployeeModel()
                                {
                                    ID = q.ID,
                                    Name= q.Name
                                }).ToList()
                      });
   return departments.ToList();
}

с помощью этой функции:

public static IQueryable<CustomEmployeeModel> ToModel(this IQueryable<employee> Employee)
    {
        return Employee.Select(u => new CustomEmployeeModel()
        {
            ID = u.ID,
            Name = u.Name
        });
    }

Но я всегда получаю сообщение об ошибке: «LINQ to Entities не распознает метод ToModel».

Я безуспешно пытался использовать его следующим образом:

Employees = p.employee.AsQueryable().ToModel().ToList() //1
Employees = db.Entry(p).Collection(f => f.employee).Query().ToModel().ToList() //2

Я думаю, что мне нужно использовать что-то вроде этого:

public static System.Linq.Expressions.Expression<Func<IQueryable<employee>, IQueryable<CustomEmployeeModel>>> ToModel()
    {
        return p => p.Select(u => new CustomEmployeeModel()
        {
            ID = u.ID,
            Name = u.Name
        });
    }

но я действительно не могу понять, как его использовать.


person Simone    schedule 18.12.2014    source источник


Ответы (2)


Я думаю, что мне нужно использовать что-то вроде этого: [snip], но я действительно не могу понять, как это использовать.

Это именно то, что вам нужно, но вам также понадобится LINQKit, чтобы запрос работал. С ним ваш код будет выглядеть так:

var toModel = ToModel();

var departments2 = db.departments
    .AsExpandable()
    .Include(p => p.employee)
    .Where(p => true)
    .Select(p => new CustomDepartmentModel()
{
    ID = p.ID,
    Employees = toModel.Invoke(p.employee).ToList()
});
person svick    schedule 18.12.2014
comment
Выглядит здорово, но безопасно ли использовать LINQKit в серьезном проекте? Мне нужно быть уверенным, что код не сломается при обновлении пакетов сущностей. А как насчет методов расширения? Как вы думаете, можно ли вызвать его таким образом: p.employee.ToModel()? - person Simone; 19.12.2014
comment
@Simone LINQKit не специфичен для EF, он работает с любым IQueryable, поэтому он должен работать с любой версией EF. И я не вижу способа заставить это работать напрямую с методом расширения; LINQKit ищет вызовы своего Invoke() и обрабатывает их, но не знает, что он должен обрабатывать ваш ToModel(). - person svick; 19.12.2014

Проблема в том, что LINQ to Entities пытается преобразовать ваш метод ToModel() в SQL-запрос (поскольку это то, что должен делать LINQ to Entities), и не может найти способ сделать это, отсюда и ошибка, которую вы видеть.

Чтобы вы могли вызвать ToModel(), вам потребуется информация, уже полученная из базы данных, которая затем сделает любой запрос LINQ запросом LINQ to Objects, который будет более чем способен делать то, о чем вы просите. Вы можете сделать это, вызвав ToList() перед вызовом ToModel().

person Corey Adler    schedule 18.12.2014
comment
Я просто хочу переместить внутренний выбор во внешний метод, я все еще хочу перевести внутренний выбор в оператор sql, и я не хочу использовать ToList(), иначе он также будет запрашивать другие параметры - person Simone; 18.12.2014
comment
За исключением того, что LINQ to Entities не построен таким образом, чтобы это разрешать. Вам нужно либо сохранить внутренний выбор, либо сначала вызвать ToList. - person Corey Adler; 18.12.2014