Impossible de créer une valeur constante de type Seuls les types primitifs ou les types d'énumération sont pris en charge dans ce contexte

164

J'obtiens cette erreur pour la requête ci-dessous

Impossible de créer une valeur constante de type API.Models.PersonProtocol. Seuls les types primitifs ou les types d'énumération sont pris en charge dans ce contexte

ppCombinedci-dessous est un IEnumerableobjet de PersonProtocolType, qui est construit par concat de 2 PersonProtocollistes.

Pourquoi cela échoue-t-il? Ne pouvons-nous pas utiliser la JOINclause LINQ à l' intérieur SELECTd'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
                 })
        });
user2515186
la source

Réponses:

232

Cela ne peut pas fonctionner car il ppCombineds'agit d'une collection d'objets en mémoire et vous ne pouvez pas joindre un ensemble de données dans la base de données avec un autre ensemble de données en mémoire. Vous pouvez essayer à la place d'extraire les éléments filtrés personProtocolde la ppCombinedcollection en mémoire après avoir récupéré les autres propriétés de la base de données:

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
la source
10
La partie clé pour moi était d'ajouter .AsEnumerable () // La requête de base de données se termine ici, le reste est une requête en mémoire
Sameer Alibhai
2
@Slauma Donc, si je suis préoccupé par les performances, je devrais éviter de faire cela car cela chargerait d'abord toutes les données en mémoire, puis les interrogerait. Dois-je écrire du SQL brut pour ces scénarios?
Arvand
Il semble que @Arvand a un grand point. Si vous disposez d'un grand nombre d'enregistrements avant le filtre, cela peut réduire considérablement les ressources mémoire disponibles.
spadelives
5
@Slauma "Cela ne peut pas fonctionner car ppCombined est une collection d'objets en mémoire et vous ne pouvez pas joindre un ensemble de données dans la base de données avec un autre ensemble de données en mémoire." Où puis-je trouver de la documentation sur des choses comme celle-ci? Je ne connais vraiment pas les limites d'EF, et lorsque j'essaie de restreindre le jeu de résultats d'une requête comme celui-ci, cette incompétence se fait très sentir et me ralentit.
Nomenator
1
Bonne information. J'ajoute cette exception à ma liste des messages d'exception les moins intuitifs de tous les temps. Cela n'a de sens qu'après avoir compris pourquoi cela se produit.
DVK
2

Je ne sais pas si quelqu'un cherche cela. J'ai eu le même problème. Une sélection sur la requête, puis faire le where (ou la jointure) et utiliser la variable select a résolu le problème pour moi. (le problème était dans la collection "Réintégrations" pour moi)

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

espérons que cela aide n'importe qui.

Roelant
la source
6
zv.this.Reintegraties.FirstOrDefault().Idpotentiel NullReferenceException
2

Dans mon cas, j'ai pu résoudre le problème en procédant comme suit:

J'ai changé mon code à partir de ceci:

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

Pour ça:

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
la source
Cela ne fonctionne pas pour moi. As p1et p2sont tous deux en mémoire, qu'ils soient déclarés de manière anonyme ou par un nom de variable.
Rahat Zaman
2
Le type de variable n'est pas le problème. Dans mon cas, l'erreur a été causée parce que je faisais un .FirstOrDefault () à l'intérieur de la clause Where.
Colin
1

Cela vaut la peine d'ajouter, car l'exemple de code de l'OP ne fournit pas suffisamment de contexte pour prouver le contraire, mais j'ai également reçu cette erreur sur le code suivant:

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

Apparemment, je ne peux pas utiliser Int32.Equalsdans ce contexte pour comparer un Int32 avec un int primitif; J'ai dû (en toute sécurité) changer pour ceci:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
James Perih
la source
EF accepte Equalsparfaitement bien.
Gert Arnold
0

Ajoutez simplement AsEnumerable () etToList (), donc cela ressemble à ceci

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

ToList().AsEnumerable()
Khaled Saleh
la source
0

J'ai eu ce problème et ce que j'ai fait et résolu le problème, c'est que j'ai utilisé AsEnumerable()juste avant ma clause Join. voici ma requête:

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

Je me demandais pourquoi ce problème se produit, et maintenant je pense que c'est parce qu'après avoir effectué une requête via LINQ , le résultat sera en mémoire et non chargé dans des objets, je ne sais pas quel est cet état mais ils sont dans certains état de transition je pense. Ensuite, lorsque vous utilisez AsEnumerable()ou ToList(), etc., vous les placez dans des objets de mémoire physique et le problème est résolu.

ebrahim.mr
la source