Konstanter Wert vom Typ kann nicht erstellt werden In diesem Kontext werden nur primitive Typen oder Aufzählungstypen unterstützt

164

Ich erhalte diesen Fehler für die folgende Abfrage

Es kann kein konstanter Wert vom Typ erstellt werden API.Models.PersonProtocol. In diesem Zusammenhang werden nur primitive Typen oder Aufzählungstypen unterstützt

ppCombinedunten ist ein IEnumerableObjekt von PersonProtocolType, das durch Concat von 2 PersonProtocolListen aufgebaut ist.

Warum scheitert das? Können wir die LINQ- JOINKlausel nicht innerhalb SELECTvon a verwenden 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
                 })
        });
user2515186
quelle

Antworten:

232

Dies kann nicht funktionieren, da ppCombinedes sich um eine Sammlung von Objekten im Speicher handelt und Sie einen Datensatz in der Datenbank nicht mit einem anderen Datensatz im Speicher verknüpfen können. Sie können stattdessen versuchen, die gefilterten Elemente personProtocolder ppCombinedSammlung im Speicher zu extrahieren, nachdem Sie die anderen Eigenschaften aus der Datenbank abgerufen haben:

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()
        });
Slauma
quelle
10
Der wichtigste Teil für mich war das Hinzufügen von .AsEnumerable () // Datenbankabfrage endet hier, der Rest ist eine Abfrage im Speicher
Sameer Alibhai
2
@Slauma Wenn ich also über die Leistung besorgt bin, sollte ich dies vermeiden, da alle Daten zuerst in den Speicher geladen und dann abgefragt werden. Sollte ich für diese Szenarien Raw SQL schreiben?
Arvand
Es scheint, als hätte @Arvand einen großartigen Punkt. Wenn Sie vor dem Filter eine große Anzahl von Datensätzen haben, kann dies die verfügbaren Speicherressourcen erheblich entlasten.
Spadelives
5
@Slauma "Dies kann nicht funktionieren, da ppCombined eine Sammlung von Objekten im Speicher ist und Sie einen Datensatz in der Datenbank nicht mit einem anderen Datensatz im Speicher verknüpfen können." Wo finde ich Dokumentation zu solchen Dingen? Mir fehlen wirklich die Kenntnisse über die Grenzen von EF, und wenn ich versuche, die Ergebnismenge einer Abfrage so einzuschränken, macht sich diese Inkompetenz sehr deutlich und verlangsamt mich.
Nomenator
1
Gute Information. Ich füge diese Ausnahme meiner Liste der am wenigsten intuitiven Ausnahmemeldungen aller Zeiten hinzu. Es macht nur Sinn, nachdem Sie verstanden haben, warum es passiert.
DVK
2

Ich weiß nicht, ob jemand danach sucht. Ich hatte das gleiche Problem. Eine Auswahl in der Abfrage und dann das Wo (oder Verbinden) und die Verwendung der Auswahlvariablen lösten das Problem für mich. (Problem war in der Sammlung "Reintegraties" für mich)

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

hoffe das hilft jedem.

Roelant
quelle
6
zv.this.Reintegraties.FirstOrDefault().Idmögliche NullReferenceException
2

In meinem Fall konnte ich das Problem folgendermaßen beheben:

Ich habe meinen Code geändert:

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

Dazu:

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();
Colin
quelle
Das funktioniert bei mir nicht. As p1und p2sind beide im Speicher, unabhängig davon, ob sie anonym oder mit einem Variablennamen deklariert sind.
Rahat Zaman
2
Der Variablentyp ist nicht das Problem. In meinem Fall wurde der Fehler verursacht, weil ein .FirstOrDefault () innerhalb der Where-Klausel ausgeführt wurde.
Colin
2

Es lohnt sich hinzuzufügen, da das Codebeispiel des OP nicht genügend Kontext bietet, um das Gegenteil zu beweisen, aber ich habe diesen Fehler auch für den folgenden Code erhalten:

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

Anscheinend kann ich Int32.Equalsin diesem Zusammenhang kein Int32 mit einem primitiven Int vergleichen. Ich musste (sicher) dazu wechseln:

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

Fügen Sie einfach AsEnumerable () und ToList () hinzu, damit es so aussieht

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

ToList().AsEnumerable()
khaled saleh
quelle