¿Por qué no puedo usar ToListAsync () cuando uso un parámetro para el predicado en EF7?

asp.net-core c# entity-framework-core

Pregunta

Actualmente estoy implementando el patrón de repositorio para mi aplicación ASP.VNext. Me gustaría que los métodos fueran asíncronos y filtrables. Así que he ideado el siguiente método de interfaz:

Task<TEntity> GetOneAsync(Func<TEntity,bool> predicate);

y me gustaría implementarlo de esta manera (con una instancia privada de DbContext ctx ):

public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate) 
{
    // compiler error
    return await ctx.MyEntities.Where(predicate).FirstOrDefaultAsync();
}

Sin embargo, solo puedo usar FirstOrDefaultAsync() cuando codifique el predicado de esta manera:

return await ctx.MyEntites.Where(e => e.Id == 1).FirstOrDefaultAsync();

Al pasar el predicado solo obtengo FirstOrDefault() sin la opción asíncrona, así que para hacer mi método asíncrono tengo que escribir

public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate) 
{
    //save to a local variable to prevent calling a disposed DbContext
    var entities = await Task.Run(() => ctx.Contracts.Where(predicate).FirstOrDefault());
    return entities;
}

Tengo dos preguntas con respecto a esto:

  1. ¿Por qué no es posible acceder al método FirstOrDefaultAsync() cuando se pasa un predicado?

  2. ¿Mi solución que utiliza await Task.Run(synchronousMethod) logra el mismo comportamiento que una llamada a FirstOrDefaultAsync() ?

Respuesta aceptada

FirstOrDefaultAsync se define como un método de extensión para IQueryable<T> .

ctx.MyEntities.Where(e => e.Id == 1) devuelve IQueryable<MyEntity> .

ctx.MyEntities.Where(predicate) devuelve IEnumerable<MyEntity> , porque está llamando al método de extensión Enumerable.Where , no a Queryable.Where .

Para que funcione, cambie el predicate de Func<MyEntity, bool> a Expression<Func<MyEntity, bool>> . Esto significa que el predicate ya no es solo una función que da el resultado que desea, sino una descripción de esa función, que Entity Framework puede traducir a SQL.

Y no, usar Func<MyEntity, bool> dentro de una tarea no tendría el mismo comportamiento. Eso cargaría filas desde el servidor db sin ningún filtro, y evaluaría todas y cada una en el cliente db hasta que se encuentre una coincidencia. Eso agregaría una gran cantidad de gastos generales.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué