Pregunta

Dada la siguiente consulta de LINQ a SQL:

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

La declaración SQL interpretada es:

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

Digamos que quería realizar alguna acción en la selección que no se puede convertir a SQL.Tengo entendido 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 donde en la instrucción SQL ejecutada.

¿Significa esto que toda la tabla "Importaciones" está almacenada en la memoria caché?¿Esto ralentizaría el rendimiento si la tabla contuviera una gran cantidad de registros?

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

¿Fue útil?

Solución

La razón por Como enumerable Es para

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

Así que cuando estabas llamando al Where método antes, estabas llamando a un diferente Where método de la IEnumerable.Where.Eso Where La declaración era para que LINQ se convirtiera a SQL, el nuevo Where es el IEnumerable uno que toma un IEnumerable, lo enumera y produce los elementos coincidentes.Lo que explica por qué ves que se generan diferentes SQL.La tabla se tomará en su totalidad de la base de datos antes de la Where La extensión se aplicará en su segunda versión del código.Esto podría crear un cuello de botella grave, porque toda la tabla tiene que estar en la memoria o, peor aún, toda la tabla tendría que viajar entre servidores.Permitir que el servidor SQL ejecute el Where y hacer lo que mejor sabe hacer.

Otros consejos

En el punto en el que se enumera la enumeración, se consultará la base de datos y se consultará todo el resultado 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 el resultado de NondatabaseconvertableCritable requiere el campo C del resultado.Debido a que Nondatabaseconvertablecitriterriterion hace lo que su nombre sugiere, esto debe realizarse como 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 se enumere la RES, se consulta o se usa de otra manera, la mayor cantidad de trabajo posible se pasará a la base de datos, lo que devolverá lo suficiente para continuar con el trabajo.Suponiendo que es realmente imposible volver a escribir para que todo el trabajo pueda enviarse a la base de datos, este puede ser un compromiso adecuado.

Hay tres implementaciones de AsEnumerable.

DataTableExtensions.AsEnumerable

Extiende un DataTable para darle un IEnumerable interfaz para que puedas usar Linq contra el DataTable.

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

El AsEnumerable<TSource>(IEnumerable<TSource>) El método 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> sí mismo.

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

En otras palabras.

si tengo un

IQueryable<X> sequence = ...;

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

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

esa consulta se redactará 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 se ejecute la declaración con Linq to Objects, lo hago,

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

ahora el servidor devolverá todos los datos y el Enumerable.Where de Linq a Objetos se utilizará en lugar de la implementación del Proveedor de consultas.

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

Creo que el asenumenable solo le dice al compilador qué métodos de extensión deben usar (en este caso, los definidos para iEnumerable en lugar de aquellos para iQeryable). La ejecución de la consulta aún se aplaza hasta que llame a Toarray o enumere en él.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top