No se puede crear un valor constante de tipo Solo se admiten tipos primitivos o tipos de enumeración en este contexto

164

Recibo este error para la consulta a continuación

No se puede crear un valor constante de tipo API.Models.PersonProtocol. Solo los tipos primitivos o los tipos de enumeración son compatibles en este contexto

ppCombineda continuación es un IEnumerableobjeto de PersonProtocolType, que está construido por concat de 2 PersonProtocollistas.

¿Por qué está fallando esto? ¿No podemos usar la JOINcláusula LINQ dentro SELECTde a 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
                 })
        });
usuario2515186
fuente

Respuestas:

232

Esto no puede funcionar porque ppCombinedes una colección de objetos en la memoria y no puede unir un conjunto de datos en la base de datos con otro conjunto de datos que está en la memoria. En su lugar, puede intentar extraer los elementos filtrados personProtocolde la ppCombinedcolección en la memoria después de haber recuperado las otras propiedades de la base de datos:

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
fuente
10
La parte clave para mí fue agregar .AsEnumerable () // la consulta de la base de datos termina aquí, el resto es una consulta en memoria
Sameer Alibhai
2
@Slauma Entonces, si me preocupa el rendimiento, debería evitar hacer esto, ya que primero cargaría todos los datos en la memoria y luego lo consultaría. ¿Debo escribir sql sin formato para estos escenarios?
Arvand
Parece que @Arvand tiene un gran punto. Si tiene una gran cantidad de registros antes del filtro, esto podría reducir enormemente los recursos de memoria disponibles.
Spadelives
55
@Slauma "Esto no puede funcionar porque ppCombined es una colección de objetos en memoria y no puede unir un conjunto de datos en la base de datos con otro conjunto de datos que está en la memoria". ¿Dónde puedo encontrar documentación sobre cosas como esta? Realmente me falta el conocimiento de los límites de EF, y cuando trato de restringir el conjunto de resultados de una consulta de esta manera, esta incompetencia se hace muy evidente y me frena.
Nomenator
1
Buena información. Estoy agregando esta excepción a mi lista de mensajes de excepción menos intuitivos. Solo tiene sentido DESPUÉS de que entiendas por qué está sucediendo.
DVK
2

No sé si alguien busca esto. Yo tuve el mismo problema. Una selección en la consulta y luego hacer el where (o join) y usar la variable select me resolvió el problema. (El problema estaba en la colección "Reintegraties" para mí)

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

Espero que esto ayude a cualquiera.

Roelant
fuente
66
zv.this.Reintegraties.FirstOrDefault().Idpotencial NullReferenceException
2

En mi caso, pude resolver el problema haciendo lo siguiente:

Cambié mi código de esto:

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

A esto:

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
fuente
Esto no funciona para mi. Como p1y p2están ambos en la memoria, ya sea que se declaren anónimamente o por un nombre de variable.
Rahat Zaman
2
El tipo de variable no es el problema. En mi caso, el error fue causado porque estaba haciendo un .FirstOrDefault () dentro de la cláusula Where.
Colin
2

Vale la pena agregarlo, ya que el ejemplo de código del OP no proporciona suficiente contexto para demostrar lo contrario, pero también recibí este error en el siguiente código:

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

Aparentemente, no puedo usar Int32.Equalsen este contexto para comparar un Int32 con un int primitivo; Tuve que (con seguridad) cambiar a esto:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
James Perih
fuente
EF acepta Equalsperfectamente bien.
Gert Arnold
0

Simplemente agregue AsEnumerable () y ToList (), para que se vea así

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

ToList().AsEnumerable()
Khaled Saleh
fuente
0

Tuve este problema y lo que hice y resolví fue que lo usé AsEnumerable()justo antes de mi cláusula Join. Aquí está mi consulta:

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

Me preguntaba por qué ocurre este problema, y ​​ahora creo que es porque después de realizar una consulta a través de LINQ , el resultado estará en la memoria y no se cargará en los objetos, no sé cuál es ese estado, pero están en algunos estado de transición , creo. Luego, cuando usa AsEnumerable()o ToList(), etc., los está colocando en objetos de memoria física y el problema se está resolviendo.

ebrahim.mr
fuente