c# - framework - ¿Cuál es el propósito de AsQueryable()?
iqueryable example c# (5)
¿El propósito de AsQueryable()
es que pueda pasar un IEnumerable
a los métodos que pueden esperar IQueryable
, o existe una razón útil para representar IQueryable
como IEnumerable
? Por ejemplo, se supone que es para casos como este:
IEnumerable<Order> orders = orderRepo.GetAll();
// I don''t want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());
public static int CountOrders(IQueryable<Order> ordersQuery)
{
return ordersQuery.Count();
}
¿O realmente hace que haga algo diferente?
IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();
IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);
// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();
¿Las versiones de IQueryable
de estos métodos de extensión simplemente crean una Expresión que termina haciendo lo mismo una vez que se ejecuta? Mi pregunta principal es, ¿cuál es el verdadero caso de uso para usar AsQueryable
?
Como notó sanjuro, el propósito de AsQueryable () se explica en Usar AsQueryable con Linq To Objects y Linq To SQL . En particular, el artículo dice:
Esto ofrece excelentes beneficios en escenarios de palabras reales donde tiene ciertos métodos en una entidad que devuelve un IQueryable de T y algunos métodos devuelven Lista. Pero luego tiene un filtro de reglas empresariales que debe aplicarse a toda la colección independientemente de si la colección se devuelve como IQueryable de T o IEnumerable of T. Desde un punto de vista de rendimiento, realmente desea aprovechar la ejecución del filtro de negocios en la base de datos si la colección implementa IQueryable; de lo contrario, retrocede para aplicar el filtro empresarial en la memoria utilizando Linq para objetar la implementación de delegados.
Documentación de cotización de interfaz IQueryable
:
La interfaz IQueryable está pensada para ser implementada por los proveedores de consultas.
Entonces, para alguien que intenta hacer que su datastracture sea consultable en .NET, esa estructura de datos que no es necesaria puede enumerarse o tener un enumerador válido .
IEnumerator
es una interfaz para iterar y procesar la secuencia de datos en su lugar.
El caso más válido que tengo para AsQueryable es la prueba unitaria. Digamos que tengo el siguiente ejemplo algo artificial
public interface IWidgetRepository
{
IQueryable<Widget> Retrieve();
}
public class WidgetController
{
public IWidgetRepository WidgetRepository {get; set;}
public IQueryable<Widget> Get()
{
return WidgetRepository.Retrieve();
}
}
y quiero escribir una prueba unitaria para asegurarme de que el controlador devuelve los resultados devueltos del repositorio. Se vería algo como esto:
[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{
var widget1 = new Widget();
var widget2 = new Widget();
var listOfWidgets = new List<Widget>() {widget1, widget2};
var widgetRepository = new Mock<IWidgetRepository>();
widgetRepository.Setup(r => r.Retrieve())
.Returns(listOfWidgets.AsQueryable());
var controller = new WidgetController();
controller.WidgetRepository = widgetRepository.Object;
var results = controller.Get();
Assert.AreEqual(2, results.Count());
Assert.IsTrue(results.Contains(widget1));
Assert.IsTrue(results.Contains(widget2));
}
donde realmente, todo el método AsQueryable () me permite hacer es satisfacer al compilador al configurar un simulacro.
Sin embargo, me interesaría saber dónde se usa esto en el código de la aplicación.
El propósito de AsQueryable () se explica en gran medida en este artículo Uso de AsQueryable con Linq a objetos y Linq a SQL
Desde la sección Observaciones del método MSDN Queryable.AsQueryable:
Si el tipo de fuente implementa IQueryable, AsQueryable (IEnumerable) lo devuelve directamente. De lo contrario, devuelve un IQueryable que ejecuta consultas llamando a los métodos de operador de consulta equivalentes en Enumerable en lugar de los que se encuentran en Queryable.
Eso es exactamente lo que se menciona y usa en el artículo anterior. En su ejemplo, depende de lo que sea orderRepo.GetAll return, IEnumerable o IQueryable (Linq to Sql). Si devuelve IQueryable, el método Count () se ejecutará en la base de datos, de lo contrario se ejecutará en la memoria. Mire cuidadosamente el ejemplo en el artículo al que se hace referencia.
Hay algunos usos principales.
Como se menciona en otras respuestas, puede usarlo para simular una fuente de datos consultable utilizando una fuente de datos en memoria para que pueda probar más fácilmente los métodos que eventualmente se usarán en un
IQueryable
no enumerable.Puede escribir métodos de ayuda para manipular colecciones que pueden aplicarse a secuencias en memoria o fuentes de datos externas. Si escribe sus métodos de ayuda para usar
IQueryable
completo, puede usarAsQueryable
en todos los enumerables para usarlos. Esto le permite evitar escribir dos versiones separadas de métodos de ayuda muy generalizados.Le permite cambiar el tipo de tiempo de compilación de un objeto consultable para que sea un
IQueryable
, en lugar de otro tipo derivado. En efecto; loAsEnumerable
en unIEnumerable
al mismo tiempo que utilizaríasAsEnumerable
en unIEnumerable
. Es posible que tenga un objeto que implementeIQueryable
pero que también tenga un métodoSelect
instancia. Si ese fuera el caso, y quisiera usar el método LINQSelect
, necesitaría cambiar el tipo de tiempo de compilación del objeto aIQueryable
. Podrías simplementeAsQueryable
, pero al tener un métodoAsQueryable
puedes aprovechar la inferencia de tipo. Esto es simplemente más conveniente si la lista de argumentos genéricos es compleja, y en realidad es necesaria si alguno de los argumentos genéricos son tipos anónimos.