Impossibile creare un valore costante di tipo In questo contesto sono supportati solo tipi primitivi o tipi di enumerazione


164

Ricevo questo errore per la query di seguito

Impossibile creare un valore costante di tipo API.Models.PersonProtocol. In questo contesto sono supportati solo tipi primitivi o tipi di enumerazione

ppCombinedsotto è un IEnumerableoggetto di PersonProtocolType, che è costruito da concat di 2 PersonProtocolliste.

Perché questo sta fallendo? Non possiamo usare la JOINclausola LINQ all'interno SELECTdi un JOIN?

var persons = db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
        new PersonDTO
        {
            personId = y.personId,
            addressId = y.addressId,                   
            favoriteId = x.favoriteId,
            personProtocol = (ICollection<PersonProtocol>) ppCombined
                .Where(a => a.personId == x.personId)
                .Select( b => new PersonProtocol()
                 {
                     personProtocolId = b.personProtocolId,
                     activateDt = b.activateDt,
                     personId = b.personId
                 })
        });


Risposte:


232

Questo non può funzionare perché ppCombinedè una raccolta di oggetti in memoria e non è possibile unire un set di dati nel database con un altro set di dati in memoria. Puoi invece provare a estrarre gli elementi filtrati personProtocoldella ppCombinedraccolta in memoria dopo aver recuperato le altre proprietà dal database:

var persons = db.Favorites
    .Where(f => f.userId == userId)
    .Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
        new // anonymous object
        {
            personId = p.personId,
            addressId = p.addressId,   
            favoriteId = f.favoriteId,
        })
    .AsEnumerable() // database query ends here, the rest is a query in memory
    .Select(x =>
        new PersonDTO
        {
            personId = x.personId,
            addressId = x.addressId,   
            favoriteId = x.favoriteId,
            personProtocol = ppCombined
                .Where(p => p.personId == x.personId)
                .Select(p => new PersonProtocol
                {
                    personProtocolId = p.personProtocolId,
                    activateDt = p.activateDt,
                    personId = p.personId
                })
                .ToList()
        });

10
La parte chiave per me è stata l'aggiunta di .AsEnumerable () // la query del database termina qui, il resto è una query in memoria
Sameer Alibhai

2
@Slauma Quindi, se sono preoccupato per le prestazioni, dovrei evitare di farlo, poiché prima carica tutti i dati in memoria e quindi li interroga. Dovrei scrivere sql grezzo per questi scenari?
Arvand,

Sembra che @Arvand abbia un ottimo punto. Se hai un gran numero di record prima del filtro, questo potrebbe richiedere un enorme morso delle risorse di memoria disponibili.
spadelives il

5
@Slauma "Questo non può funzionare perché ppCombined è una raccolta di oggetti in memoria e non è possibile unire un set di dati nel database con un altro set di dati in memoria." Dove posso trovare documentazione su cose come questa? Mi manca davvero la conoscenza dei limiti di EF e quando provo a limitare il set di risultati di una query in questo modo, questa incompetenza si rende molto evidente e mi rallenta.
Nomenator,

1
Buona informazione Sto aggiungendo questa eccezione al mio elenco di messaggi di eccezione meno intuitivi di sempre. Ha senso solo dopo aver capito perché sta accadendo.
DVK

2

Non so se qualcuno cerca questo. Ho avuto lo stesso problema. Una selezione sulla query e quindi facendo dove (o unendo) e usando la variabile select risolto il problema per me. (il problema era nella raccolta "Reintegraties" per me)

query.Select(zv => new
            {
                zv,
                rId = zv.this.Reintegraties.FirstOrDefault().Id
            })
            .Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
                                             && t.HoortBijEntiteitType == EntiteitType.Reintegratie
                                             && t.Type == TaakType))
            .Select(x => x.zv);

spero che questo aiuti chiunque.


6
zv.this.Reintegraties.FirstOrDefault().Idpotenziale NullReferenceException

2

Nel mio caso, sono stato in grado di risolvere il problema procedendo come segue:

Ho cambiato il mio codice da questo:

var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();

A questa:

var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();

Questo non funziona per me. Come p1e p2sono entrambi nella memoria sia che siano dichiarati in forma anonima o con un nome variabile.
Rahat Zaman,

2
Il tipo di variabile non è il problema. Nel mio caso l'errore è stato causato perché stava facendo un .FirstOrDefault () all'interno della clausola Where.
Colin,

1

Vale la pena aggiungere, poiché l'esempio di codice del PO non fornisce un contesto sufficiente per provare il contrario, ma ho ricevuto questo errore anche sul seguente codice:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
        .FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}

Apparentemente, non posso usare Int32.Equalsin questo contesto per confrontare un Int32 con un int primitivo; Ho dovuto (in modo sicuro) passare a questo:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}

EF accetta Equalsperfettamente bene.
Gert Arnold,

0

Aggiungi AsEnumerable () andToList (), quindi è così

db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()

ToList().AsEnumerable()

0

Ho avuto questo problema e quello che ho fatto e risolto il problema è che ho usato AsEnumerable()poco prima della mia clausola Join. ecco la mia domanda:

List<AccountViewModel> selectedAccounts;

 using (ctx = SmallContext.GetInstance()) {
                var data = ctx.Transactions.
                    Include(x => x.Source).
                    Include(x => x.Relation).
                    AsEnumerable().
                    Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
                    GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
                    ToList();
            }

Mi chiedevo perché questo problema si verifica, e ora penso che sia perché dopo aver effettuato una query tramite LINQ , il risultato sarà in memoria e non caricato in oggetti, non so quale sia lo stato ma sono presenti in alcuni stato di transizione penso. Quindi quando si utilizza AsEnumerable()o ToList(), ecc., Li si inserisce in oggetti di memoria fisica e il problema si sta risolvendo.

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.