example consulta c# linq linq-to-sql asenumerable

c# - consulta - linq result to datatable



Comprender.AsEnumerable() en LINQ to SQL (4)

Creo que AsEnumerable simplemente le dice al compilador qué métodos de extensión usar (en este caso, los definidos para IEnumerable en lugar de los de IQueryable). La ejecución de la consulta aún se aplaza hasta que llame a ToArray o enumere en ella.

Dada la siguiente consulta de LINQ a SQL:

var test = from i in Imports where i.IsActive select i;

La instrucción SQL interpretada es:

SELECT [t0].[id] AS [Id] .... FROM [Imports] AS [t0] WHERE [t0].[isActive] = 1

Supongamos que quería realizar alguna acción en la selección que no se puede convertir a SQL. Entiendo que la forma convencional de lograr esto es hacer AsEnumerable() convirtiéndolo así en un objeto viable.

Dado este código actualizado:

var test = from i in Imports.AsEnumerable() where i.IsActive select new { // Make some method call };

Y SQL actualizado:

SELECT [t0].[id] AS [Id] ... FROM [Imports] AS [t0]

Observe la falta de una cláusula where en la instrucción SQL ejecutada.

¿Esto significa que toda la tabla de "Importaciones" está almacenada en la memoria? ¿Disminuiría este rendimiento si la tabla contuviera una gran cantidad de registros?

Ayúdame a entender lo que está sucediendo detrás de escena aquí.


En el punto donde se enumera la enumeración, se consultará la base de datos y se recuperará todo el conjunto de resultados.

Una solución de parte y parte puede ser el camino. Considerar

var res = ( from result in SomeSource where DatabaseConvertableCriterion(result) && NonDatabaseConvertableCriterion(result) select new {result.A, result.B} );

Digamos también que NonDatabaseConvertableCriterion requiere el campo C del resultado. Como NonDatabaseConvertableCriterion hace lo que sugiere su nombre, esto debe realizarse como una enumeración. Sin embargo, considere:

var partWay = ( from result in SomeSource where DatabaseConvertableCriterion(result) select new {result.A, result.B, result.C} ); var res = ( from result in partWay.AsEnumerable() where NonDatabaseConvertableCriterion select new {result.A, result.B} );

En este caso, cuando res se enumera, se consulta o se utiliza de otra forma, se pasará a la base de datos el mayor trabajo posible, que devolverá lo suficiente como para continuar el trabajo. Suponiendo que realmente es realmente imposible reescribir para que todo el trabajo pueda enviarse a la base de datos, esto puede ser un compromiso adecuado.


Hay tres implementaciones de AsEnumerable .

DataTableExtensions.AsEnumerable

Extiende una DataTable para darle una interfaz IEnumerable para que pueda usar Linq contra la DataTable .

Enumerable.AsEnumerable<TSource> y ParallelEnumerable.AsEnumerable<TSource>

El AsEnumerable<TSource>(IEnumerable<TSource>) no tiene otro efecto que cambiar el tipo de fuente de tiempo de compilación de un tipo que implementa IEnumerable<T> a IEnumerable<T> .

AsEnumerable<TSource>(IEnumerable<TSource>) se puede usar para elegir entre implementaciones de consulta cuando una secuencia implementa IEnumerable<T> pero también tiene un conjunto diferente de métodos de consulta pública disponibles. Por ejemplo, dada una Table clase genérica que implementa IEnumerable<T> y tiene sus propios métodos como Where , Select y SelectMany , una llamada a Where invocaría el método Where público de Table . Un tipo de Table que represente una tabla de base de datos podría tener un método Where que tome el argumento de predicado como un árbol de expresión y convierta el árbol a SQL para su ejecución remota. Si no se desea la ejecución remota, por ejemplo, porque el predicado invoca un método local, el método AsEnumerable<TSource> se puede utilizar para ocultar los métodos personalizados y, en su lugar, poner a disposición los operadores de consulta estándar.

En otras palabras.

Si tengo un

IQueryable<X> sequence = ...;

de un LinqProvider, como Entity Framework, y lo hago,

sequence.Where(x => SomeUnusualPredicate(x));

esa consulta se compondrá y ejecutará en el servidor. Esto fallará en tiempo de ejecución porque EntityFramework no sabe cómo convertir SomeUnusualPredicate en SQL.

Si quiero que ejecute la declaración con Linq to Objects en su lugar, lo hago,

sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));

ahora el servidor devolverá todos los datos y el Enumerable.Where Desde Linq hasta Objects se usará en lugar de la implementación del Proveedor de consultas.

No importará que Entity Framework no sepa cómo interpretar SomeUnusualPredicate , mi función se usará directamente. (Sin embargo, este puede ser un enfoque ineficiente ya que todas las filas serán devueltas desde el servidor).


La razón de AsEnumerable es

AsEnumerable (TSource) (IEnumerable (TSource)) se puede usar para elegir entre implementaciones de consulta cuando una secuencia implementa IEnumerable (T) pero también tiene un conjunto diferente de métodos de consulta pública disponibles

Entonces, cuando llamabas al método Where anteriormente, llamabas a un método Where diferente desde IEnumerable.Where. Esa declaración Donde era para LINQ convertir a SQL, el nuevo ¿Dónde está el IEnumerable que toma un IEnumerable, lo enumera y cede los elementos coincidentes. Lo que explica por qué ves los diferentes SQL que se generan. La tabla se tomará en su totalidad de la base de datos antes de que se aplique la extensión Where en su segunda versión del código. Esto podría crear un cuello de botella grave, porque toda la tabla debe estar en la memoria, o peor, toda la mesa debería viajar entre servidores. Permita que SQL Server ejecute Where y haga lo que mejor hace.