Sono supportati solo gli inizializzatori, i membri dell'entità e le proprietà di navigazione dell'entità


102

Ricevo questa eccezione:

Il membro del tipo specificato "Paid" non è supportato in LINQ to Entities. Sono supportati solo gli inizializzatori, i membri dell'entità e le proprietà di navigazione dell'entità.

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

        return View(debts);
    }

La mia classe di modello

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

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

Pagamenti è una tabella correlata contenente l'importo del campo, la query funziona se rimuovo la clausola Where che mostra le informazioni corrette sui pagamenti, qualche indizio su cosa c'è che non va nel codice?

Risolto come la risposta suggerita con:

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

        return View(debts);
    }

15
Risposta semplice: non è possibile utilizzare proprietà non mappate nelle query linq-to-entity! Solo le proprietà mappate vengono tradotte in SQL.
Ladislav Mrnka

Risposte:


114

L'entità sta tentando di convertire la tua proprietà a pagamento in SQL e non può perché non fa parte dello schema della tabella.

Quello che puoi fare è lasciare che Entity interroghi la tabella senza filtri a pagamento e quindi filtrare quelli non a pagamento.

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

Ciò, ovviamente, significherebbe riportare tutti i dati sul server web e filtrare i dati su di esso. Se si desidera filtrare sul server DB, è possibile creare una colonna calcolata sulla tabella o utilizzare una stored procedure.


25

Dovevo solo risolvere un problema simile. Le soluzioni precedenti richiedono l'elaborazione in memoria, che è una cattiva pratica (caricamento lento).

La mia soluzione era scrivere un helper che restituisse un predicato:

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

Puoi riscrivere la tua dichiarazione linq come:

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

Ciò è utile quando si desidera riutilizzare la logica di calcolo (DRY). Lo svantaggio è che la logica non è nel tuo modello di dominio.


1
Esistono numerose librerie che tentano di rendere questo approccio più "integrato", vedere: stackoverflow.com/a/27383641/470183 . Linq-to-entity è limitato alle espressioni che utilizzano le "Funzioni canoniche", che possono essere trasformate in SQL. C # 6 ha introdotto "funzioni con corpo di espressione" ma queste non sono veri lambda (vedere: stackoverflow.com/a/28411444/470183 ). Tuttavia sarebbe bene avere questo nel framework, quindi WIBNI data.uservoice.com/forums/…
James Close

1
Grazie per questo semplice e conciso esempio di Expression<Func<xx,yy>>. L'ho mai capito prima, ma ora sembra ovvio.
AlexB

17

Questo problema può anche derivare da una [NotMapped]proprietà che ha lo stesso nome nel modello DB e nel modello di visualizzazione.

AutoMapper prova a selezionarlo dal DB durante una proiezione; e la proprietà NotMapped ovviamente non esiste nel DB.

La soluzione è Ignorela proprietà nella configurazione AutoMapper durante la mappatura dal modello DB al modello di visualizzazione.

  1. Cerca una [NotMapped]proprietà con nome Foonel tuo modello DB.
  2. Cerca una proprietà con lo stesso nome Foo,, nel tuo modello di visualizzazione.
  3. In tal caso, modificare la configurazione di AutoMapper. Inserisci.ForMember(a => a.Foo, b => b.Ignore());

Dang AutoMapper Projection ha colto anche me, grazie per la risposta!
Chase Florell

15

Linq converte le istruzioni in istruzioni SQL e le esegue nel database.

Ora, questa conversione si verifica solo per i membri delle entità, gli inizializzatori e le proprietà di navigazione delle entità. Quindi, per ottenere la funzione o ottenere il confronto delle proprietà, dobbiamo prima convertirli in elenchi in memoria e quindi applicare la funzione per recuperare i dati.

Quindi nella totalità,

var debts = storeDB.Orders.toList()
        .Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);

21
Suggerirei che chiedere a qualcuno di creare un toList () sugli ordini è pericoloso poiché significherebbe recuperare l'intera lista
elgrego

Questo è positivo per me perché la mia proprietà problematica è in una funzione Sum Linq non nella clausola Where. Quindi non ricevo dati non necessari e sui dati recuperati sto eseguendo la funzione Linq Sum che sta lavorando su List. Grazie! Ciò che può sembrare brutto all'inizio può essere molto utile in determinate situazioni!
Dov Miller

11

L'altro motivo probabile è perché stai usando IEnumerableper la tua proprietà, invece diICollection

Quindi invece di:

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

Fai questo:

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

E tu sei Hunky Dory ... cosa stupida da perdere per 2 ore.


2

Questa situazione può verificarsi anche se utilizzi tipi non supportati da EntityFramework , come unsigned int.

Questo è stato il mio caso di tale errore.

Controlla ulteriori informazioni sui tipi supportati: https://msdn.microsoft.com/en-us/library/ee382832(v=vs.100).aspx

Esiste una soluzione alternativa per tali situazioni, spiegata da GFoley83: come utilizzare i tipi int / long senza segno con Entity Framework?


Questo collegamento ha risparmiato parecchio tempo! Grazie mille!
Vladimir Semashkin

0

Ho affrontato questo problema perché avevo una variabile membro con solo get without setproprietà

questo significa che è auto calculatede not storedcome colonna inthe table

quindi è not existintable schema

in modo make sureche ogni membro variabile not auto calculatedad haveuna gettere setterproprietà


-1

il tuo edmx e il tuo modello di contesto hanno alcune proprietà diverse che sono state recentemente aggiunte in db.

Aggiorna il tuo EDMX aggiornalo correttamente Bulid il tuo progetto ed esegui di nuovo.

Risolverà il tuo problema.

Saluti, Ganesh Nikam

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.