2009-09-01 27 views
14

Estoy utilizando LINQ to SQL para obtener un resultado de búsqueda de un procedimiento almacenado FullTextSearch en el servidor Sql 2008. Arrastré el procedimiento desde el explorador del servidor al diseñador y obtuve el método creado con el tipo de devolución y los parámetros adecuados. Ahora el problema es que necesito obtener el conteo del resultado de llamar a este método, así que usando mi método de repositorio (que llamará al método Sproc y devolveré el resultado como IQueryable) hago la siguiente llamada.¿Los resultados de la consulta no se pueden enumerar más de una vez?

var result = repository.FullTextSearch(searchText); 
     int resultsCount = result.Count(); 
     var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList(); 

Este código genera un InvalidOperationException cada vez que intento ejecutarlo, a excepción dice (sí, lo has adivinado!) "Los resultados de la consulta no se pueden enumerar más de una vez."

El método que se generó para Sproc devuelve ISingleResult que debe ser O.K. HASTA DONDE SE. Necesito apoyar la búsqueda en mi vista, así que necesito saber el número total de páginas, lo cual (AFAIK nuevamente) solo es posible si puedo obtener el conteo de todos los artículos.

¿Qué me falta aquí, muchachos?

+0

Al parecer, la refactorización sugerido por Marc Gravell es la mejor, goona hacer esto una vez que tiene tiempo para ello. ¡Tomo la respuesta de Marc! Gracias otra vez Chicos! – Galilyou

Respuesta

14

Dado que se está ejecutando un procedimiento almacenado, todas sus encantadoras Skip/Take son en gran parte redundantes de todos modos ... no tiene más remedio que recuperar todos los datos (las llamadas a procedimientos almacenados no se pueden componer). Lo único que puede hacer es no materializar objetos para algunos de ellos.

Me pregunto si el mejor enfoque sería refactorizar el código para hacer dos llamadas:

int result = repository.FullTextSearchCount(searchText); 
var result = repository.FullTextSearch(searchText, skip, take); // or similar 

es decir, hacer la parte de parámetros de paginación de la sproc (y para la filtración en la base de datos, utilizando ROW_NUMBER()/OVER(...) , o tabla de variables, temp-mesas, etc) - o, alternativamente, algo similar con un parámetro OUTPUT en el sproc:

int? count = null; 
var result = repository.FullTextSearch(searchText, skip, take, ref count); 

(me parece recordar que OUTPUT se convierte en ref, ya que TSQL OUTPUT es realmente input + output)

+0

Totalmente de acuerdo en la parte de refactorización aquí, pero el tiempo no está permitiendo en este momento . Por ahora, creo que agregaré otro método al repositorio "int FullTextSearchCount()". Esto parece funcionar mientras hablo. La sugerencia de refactorización está en el To-Do ahora Marc. +1 gracias. – Galilyou

17

Lo que puede hacer es agregar una llamada ToList() después de repository.FullTextSearch(searchText). De esta forma, los resultados se recuperan del servidor, después de lo cual puede hacer con ellos lo que quiera (ya que ahora están cargados en la memoria).

Lo que intenta hacer ahora es ejecutar la misma consulta SQL dos veces, lo que es bastante ineficiente.

+2

Argumentaría que recuperar todo el resultado de FTS y materializar todo es * sustancialmente * más ineficiente que ejecutar dos (pero restringidas) consultas. –

+0

Creo que también Marc. Quiero decir que si agregué .ToList() como sugirió rwwilden, obtendré el resultado completo de la búsqueda, que puede ser enorme.No quiero obtenerlos todos ahora, solo quiero 10, es por eso que soy .Skip() ping. – Galilyou

+0

Acepto que devolver el conjunto de resultados completo al servidor es más ineficiente que realizar dos consultas. Sin embargo, dado que es una llamada a procedimiento almacenado, eso sucederá de todos modos (como Marc señaló correctamente en su respuesta). –

1

Sugeriría que si necesita el conteo, ejecute primero el resultado. y luego ejecute el conteo desde la lista misma, ya que no usa resultsCount en la ejecución de resultados.

var result = repository.FullTextSearch(searchText); 
var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList(); 
int resultsCount = ret.Count(); 
+0

La idea es que resultsCount represente la cantidad total de resultados. –

+0

¡Sí, Kamal! Necesito obtener el conteo de todos los resultados. No solo la parte parcial que voy a tomar. – Galilyou

+0

disculpas. ¡Lo extrañé! – Kamal

5

El uso de ToList() puede ayudar a evitar este problema.

var result = repository.FullTextSearch(searchText).ToList(); 
Cuestiones relacionadas