Поддерживаются только инициализаторы, члены сущности и свойства навигации сущности.

102

Я получаю это исключение:

Указанный член типа Paid не поддерживается в LINQ to Entities. Поддерживаются только инициализаторы, члены сущности и свойства навигации сущности.

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .Where(o => o.Paid == false)
            .OrderByDescending(o => o.DateCreated);

        return View(debts);
    }

Мой класс модели

public partial class Order
{
    public bool Paid {
        get {
            return TotalPaid >= Total;
        }
    }

    public decimal TotalPaid {
        get {
            return Payments.Sum(p => p.Amount);
        }
    }

Платежи - это связанная таблица, содержащая сумму поля. Запрос работает, если я удалю предложение Where, показывающее правильную информацию о платежах, есть ли подсказка, что не так с кодом?

Решено, как предложенный ответ:

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .OrderByDescending(o => o.DateCreated)
            .ToList()
            .Where(o => o.Paid == false);

        return View(debts);
    }
Марк
источник
15
Простой ответ: нельзя использовать несопоставленные свойства в запросах linq-to-entity! В SQL переводятся только сопоставленные свойства.
Ладислав Мрнка 03

Ответы:

114

Entity пытается преобразовать ваше свойство Paid в SQL и не может, потому что оно не является частью схемы таблицы.

Что вы можете сделать, так это позволить Entity запросить таблицу без платного фильтра, а затем отфильтровать неплатные.

public ActionResult Index()
{
    var debts = storeDB.Orders
        //.Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);

    debts = debts.Where(o => o.Paid == false);

    return View(debts);
}

Это, конечно, означает, что вы возвращаете все данные на веб-сервер и фильтруете данные на нем. Если вы хотите выполнить фильтрацию на сервере БД, вы можете создать вычисляемый столбец в таблице или использовать хранимую процедуру.

Евгений С.
источник
25

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

Мое решение заключалось в том, чтобы написать помощника, возвращающего предикат:

public static class Extensions
{
    public static Expression<Func<Order, bool>> IsPaid()
    {
        return order => order.Payments.Sum(p => p.Amount) >= order.Total;
    }
}

Вы можете переписать свой оператор linq как:

var debts = storeDB.Orders
                    .Where(Extensions.IsPaid())
                    .OrderByDescending(o => o.DateCreated);

Это удобно, когда вы хотите повторно использовать логику расчета (СУХОЙ). Обратной стороной является то, что логика отсутствует в вашей модели предметной области.

Коэн Луйтен
источник
1
Существует ряд библиотек, которые пытаются сделать этот подход более «встроенным», см. Stackoverflow.com/a/27383641/470183 . Linq-to-entity ограничивается выражениями, использующими «канонические функции», которые можно преобразовать в SQL. В C # 6 представлены «функции, основанные на выражениях», но это не настоящие лямбды (см. Stackoverflow.com/a/28411444/470183 ). Тем не менее, было бы хорошо, если бы это было в структуре, следовательно, WIBNI data.uservoice.com/forums/…
Джеймс Клоуз
1
Спасибо за этот простой и лаконичный пример Expression<Func<xx,yy>>. Я когда-либо понимал это раньше, но теперь это кажется очевидным.
AlexB
17

Эта проблема также может возникать из-за [NotMapped]свойства, имеющего то же имя в вашей модели БД и модели представления.

AutoMapper пытается выбрать его из БД во время проецирования; и свойство NotMapped, очевидно, не существует в БД.

Решением является Ignoreсвойство в конфигурации AutoMapper при сопоставлении модели БД с моделью представления.

  1. Найдите [NotMapped]свойство с именем Fooв вашей модели БД.
  2. Найдите свойство с тем же именем Fooв вашей модели представления.
  3. В таком случае измените конфигурацию AutoMapper. Добавить.ForMember(a => a.Foo, b => b.Ignore());
Джесс
источник
Dang AutoMapper Projection меня тоже поймал, спасибо за ответ!
Чейз Флорелл
15

Linq преобразует операторы в операторы SQL и выполняет их в базе данных.

Теперь это преобразование происходит только для членов сущностей, инициализаторов и свойств навигации сущностей. Итак, чтобы выполнить функцию или получить сравнение свойств, нам нужно сначала преобразовать их в список в памяти, а затем применить функцию для получения данных.

Поэтому в целом

var debts = storeDB.Orders.toList()
        .Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);
Т Гупта
источник
21
Я бы сказал, что просить кого-то создать toList () по заказам опасно, так как это означало бы получение всего списка
elgrego
Это хорошо для меня, потому что мое проблемное свойство находится в функции Sum Linq, а не в предложении Where. Таким образом, я не получаю ненужных данных, а на полученных данных я выполняю функцию Linq Sum, которая работает со списком. Спасибо! То, что сначала может показаться плохим, может оказаться очень полезным в определенных ситуациях!
Дов Миллер
11

Другая вероятная причина заключается в том, что вы используете IEnumerableдля своей собственности, а неICollection

Так что вместо:

public class This
{
    public long Id { get; set; }
    //...
    public virtual IEnumerable<That> Thats { get; set; }
}

Сделай это:

public class This
{
    public long Id { get; set; }
    //...
    public virtual ICollection<That> Thats { get; set; }
}

А ты здоровяк, дори ... глупо терять два часа.

Серж Саган
источник
2

Эта ситуация также может произойти, если вы используете неподдерживаемые EntityFramework типы , такие как unsigned int.

Это был мой случай такой ошибки.

Ознакомьтесь с дополнительной информацией о поддерживаемых типах: https://msdn.microsoft.com/en-us/library/ee382832(v=vs.100).aspx

GFoley83 объясняет, как можно обойти такие ситуации: как использовать беззнаковые типы int / long с Entity Framework?

Ony
источник
Эта ссылка сэкономила довольно много времени! Большое тебе спасибо!
Владимир Семашкин
0

Я столкнулся с этой проблемой, потому что у меня была переменная-член только со get without setсвойством

это означает, что это auto calculatedи not storedкак столбец вthe table

поэтому его not existвtable schema

так make sureчто любая переменная - член not auto calculatedв и свойствhavegettersetter

Башир АЛЬ-МОМАНИ
источник
-1

ваш edmx и контекстная модель имеют некоторое различное свойство, которое недавно добавлено в db.

Обновите EDMX, обновите его должным образом. Создайте свой проект и запустите снова.

Это решит вашу проблему.

С уважением, Ганеш Никам

Ганеш Никам
источник