Підтримуються лише ініціалізатори, члени об'єкта та навігаційні властивості сутності


102

Я отримую цей виняток:

Вказаний член типу "Оплачений" не підтримується в LINQ для Суб'єктів. Підтримуються лише ініціалізатори, члени об'єкта та навігаційні властивості сутності.

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

Платежі - це пов’язана таблиця, що містить суму поля. Запит працює, якщо я видаляю пункт «Де», де відображається правильна інформація про платежі, будь-який підказки, що не так з кодом?

Вирішено як відповідь, запропонована з:

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

        return View(debts);
    }

15
Проста відповідь: Ви не можете використовувати не відображені властивості у запитах linq-to-subjekt! У SQL переводяться лише відображені властивості.
Ladislav Mrnka

Відповіді:


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

Це зручно, коли потрібно повторно використовувати логіку обчислення (DRY). Недоліком є ​​те, що логіка відсутня у вашій моделі домену.


1
Існує ряд бібліотек, які намагаються зробити цей підхід більш «вбудованим» див.: Stackoverflow.com/a/27383641/470183 . Субстанції Linq-to-сущностей обмежуються виразами, використовуючи "Канонічні функції" - які можна перетворити на SQL. C # 6 введено «Вираз доданої форми функції» , але вони не є істинними лямбда (див: stackoverflow.com/a/28411444/470183 ). Але все-таки було б добре мати це в рамках, отже, WIBNI data.uservoice.com/forums/…
James Close

1
Дякую за цей простий і стислий приклад Expression<Func<xx,yy>>. Я колись це розумів, але зараз це виглядає очевидно.
AlexB

17

Ця проблема також може виникати з [NotMapped]властивості, яка має те саме ім'я у вашій моделі DB та View Model.

AutoMapper намагається вибрати його з БД під час проекції; а властивість NotMapped очевидно не існує в БД.

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

  1. Шукайте [NotMapped]властивість з назвою Fooу вашій моделі DB.
  2. Шукайте об’єкт із такою ж назвою Fooу своїй моделі перегляду.
  3. Якщо це так, то змініть конфігурацію AutoMapper. Додайте.ForMember(a => a.Foo, b => b.Ignore());

Проект Dang AutoMapper мене також зловив, дякую за відповідь!
Чейз Флорелл

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 , наприклад, непідписаний int.

Це був мій випадок такої помилки.

Отримайте додаткову інформацію про підтримувані типи: https://msdn.microsoft.com/en-us/library/ee382832(v=vs.100).aspx

Існує певне вирішення подібних ситуацій, пояснене GFoley83: Як використовувати неподписані int / long типи з Entity Framework?


Це посилання заощадило досить багато часу! Дуже дякую!
Володимир Семашкін

0

Я зіткнувся з цією проблемою, тому що мав змінну члена лише з get without setвластивістю

це означає його auto calculatedі not storedяк стовпчик вthe table

тому його not existвtable schema

так make sureщо будь-який член змінної not auto calculatedна havea getterта setterвластивості


-1

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

Оновіть оновлення EDMX належним чином. Об’єднайте проект та запустіть знову.

Це вирішить вашу проблему.

З повагою, Ганеш Нікам

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.