2009-11-17 28 views
6

Tengo una consulta de Linq a SQL muy compleja que devuelve un conjunto de resultados de una base de datos de Microsoft SQL Server. La consulta se crea utilizando una sintaxis similar a:La consulta de Linq devuelve un resultado incorrecto Conjunto

Dim db as MyDataContext = MyGetDataContextHelper() 
Dim qry = From rslt in db.MyView Select ColumnList 

If userParam1 IsNot Nothing Then 
    qry = qry.Where(lambda for the filter) 
End If 

etc.... 

Return qry.ToList() 

Hay varios filtros especificados por el usuario a la consulta, incluyendo uno que hace una búsqueda radio geográfico.

Aquí está el problema. Tengo un descanso establecido en la llamada "ToList" justo al final. Cuando se golpea la ruptura, utilizo el Visualizador de depuración de SQL para ver la declaración SQL generada. Copio esa declaración SQL compleja en una ventana de consulta de SQL Server Management Studio y la ejecuto contra mi base de datos para obtener exactamente el conjunto de resultados que deseo. Entonces, el SQL generado parece producir el resultado deseado. Sin embargo, cuando ejecuto el método "ToList" del objeto de consulta, la lista devuelta tiene menos filas y algunas filas diferentes. También he intentado esto usando la propiedad de registro DataContext escribiendo en un archivo, con el mismo resultado. La consulta genera el conjunto de resultados correcto en SQL Management Studio, pero resultados incorrectos del método ToList.

¿Cómo puede ser eso? Si el SQL generado simplemente se transfiere a través de la conexión al servidor SQL, ¿no debería generar exactamente el conjunto de resultados que veo en SQL Server Management Studio? Supongo que estoy malinterpretando algo sobre el mecanismo de Linq a SQL, es decir, que no se trata simplemente de un traspaso a SQL Server. ¿Es eso correcto?

EDIT: De acuerdo con una solicitud a continuación, aquí es una versión muy condensada del SQL que se genera por LINQ, con la mayoría de las columnas de resultados extraídos por razones de brevedad. Produce el resultado correcto en SQL Management Studio, pero el resultado devuelto a mi aplicación es diferente.

SELECT [t3].[Id] 
FROM (
    SELECT DISTINCT [t1].[Id] 
    FROM (
     SELECT [t0].[Id], [t0].[ItemDate] 
     FROM [dbo].[MySearchView] AS [t0] 
     ) AS [t1] 
    WHERE (EXISTS(
     SELECT NULL AS [EMPTY] 
     FROM [dbo].[ZipCoverage] AS [t2] 
     WHERE ([t2].[Id] = [t1].[Id]) 
     AND ([t2].[Latitude] >= (41.09046 - (0.5))) 
     AND ([t2].[Latitude] <= (41.09046 + (0.5))) 
     AND ([t2].[Longitude] >= (-73.43106 - (0.5))) 
     AND ([t2].[Longitude] <= (-73.43106 + (0.5))) 
     AND (ABS(3956.08833132861 * 2 * ATN2(SQRT(POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029)/(CONVERT(Float,2))), 2) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude]) - -1.28161377022951)/(CONVERT(Float,2))), 2))), SQRT((1 - POWER(SIN((((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) - 0.717163818159029)/(CONVERT(Float,2))), 2)) + (COS(0.717163818159029) * COS((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Latitude]) * POWER(SIN(((CONVERT(Float,CONVERT(Float,0.0174532925199433))) * [t2].[Longitude])/(CONVERT(Float,2))), 2))))) <= 5))) 
     AND ([t1].[ItemDate] <= '11/17/2009 8:12:42 PM') 
    ) AS [t3] 

ACTUALIZACIÓN 2009-11-17 fue capaz de ponerse en contacto con EM con respecto a este tema. Creé una aplicación de muestra que presenté a su representante de soporte. Han duplicado el problema y están investigando. Publicaré respuesta cuando reciba una respuesta.

ACTUALIZACIÓN 2009-12-21 Finalmente llegué a la respuesta correcta con la ayuda de Microsoft. Por favor vea mi respuesta aceptada a continuación para la explicación.

+1

¿Podría publicar su consulta LINQ real? Dijiste que era muy complejo. Dado que todo lo demás parece estar en orden, la opción restante es que su consulta LINQ contiene procesamiento solo en tiempo de ejecución que el traductor no pudo convertir en SQL. – jrista

+0

He respondido a tu comentario en mi respuesta a continuación. –

+0

¿No hay PEDIDO POR? ¿De cuántas filas estamos hablando, y cómo está validando que los resultados son diferentes? ¿Es posible que el orden sea diferente y que parezca que los resultados son diferentes? –

Respuesta

2

Bueno, después de algunos ir y venir con un representante de soporte muy útil de Microsoft, finalmente llegamos a la fuente del problema. Y lamentablemente no proporcioné información suficiente en mi publicación original para que alguien aquí en SO tome la determinación, así que mis disculpas en ese sentido.

Aquí está el tema - como parte del código que construye la consulta LINQ en cuestión, he declarado una variable .Net, así:

Dim RadCvtFactor As Decimal = Math.PI/180 

Resulta que cuando este se pasa a SQL la declaración de parámetros , como se evidencia en el archivo de registro LINQ, es DECIMAL (29, 4). Debido al valor de escala en la declaración, se pasa un valor no válido a RDBMS, lo que resulta en una extraña diferencia en los resultados de la consulta.

Declarar la variable .Net como un valor individual, así:

Dim RadCvtFactor As Single = Math.PI/180 

corrige el problema por completo.

El representante de Microsoft reconoció que la conversión de este parámetro puede ser un "problema potencial" y consultaría al equipo del producto.

Gracias a todos los que respondieron.

1

Lo único que viene inmediatamente a la mente es un problema de permiso. ¿Es posible que el programa y la consulta ejecutada manualmente se estén ejecutando con diferentes credenciales y, por lo tanto, tengan diferentes niveles de acceso a la base de datos? Eso puede influir en los resultados de la consulta.

+0

Si bien eso podría explicar las filas que faltan, creo que es muy poco probable que la misma fila aparezca de forma diferente en los dos contextos, a menos que la consulta se haya creado intencionalmente con expresiones CASE basadas en el nombre de usuario. Supongo que esto es solo una consulta SELECT y no una llamada a procedimiento almacenado (donde tal lógica podría ser invisible para Bob Mc). –

+0

Sí, es solo una consulta SELECT, no una llamada de proceso almacenada. –

+0

Ingresé a SQL Server Management Studio usando las credenciales del programa e intenté la consulta. Obtuve los resultados correctos, así que los permisos no parecen ser así. Gracias, sin embargo. –

1

Comenzaré mirando su DataContext. Si su DataContext no se está actualizando desde SQL Server, entonces puede devolver una versión anterior de la tabla.

DataContext mantiene un estado de la base de datos cuando se creó. Desea utilizar un contexto nuevo para cada conjunto de operaciones.

+0

Eso es una buena idea, tal vez intente con una consulta muy simple contra una sola fila. Actualice la fila en la base de datos y vea si Linq se pone al día. –

+0

Cuando leí esta respuesta, pensé con certeza que este era el problema, pero actualicé las tablas y vistas relevantes en el archivo DBML sin alegría. –

+0

No es el DBML, sino el DataContext real. Debería hacer Dim db como contexto = new MyDbContext() cada vez que realice una nueva operación. Si MyGetDataContextHelper() crea un contexto que resuena entre las llamadas, no tomará la tabla más reciente de la base de datos. –

1

Otra posibilidad es el nivel de aislamiento y la naturaleza de los datos. ¿Está utilizando REPEATABLE READ o READ UNCOMMITTED o SNAPSHOT en Linq? ¿Qué pasa cuando se usa SSMS? Obviamente, si los datos se mueven, un nivel de aislamiento laxo le permitirá saltear filas, leer algunas filas dos veces, ver la versión anterior de una fila, etc.

Además, ¿puede darnos una idea un poco mejor de qué? la consulta muy compleja "parece? No tiene que usar sus nombres de tablas reales.

+0

Según su solicitud, publiqué una versión condensada de la consulta generada de Linq. No estoy seguro de cómo usaré REPEATABL READ o READ UNCOMMITTED, ¿puede dar más detalles? Además, la información es muy estática, no es transaccional, es más para informar. Gracias. –

+0

No uso Linq pero tengo entendido que puede establecer explícitamente el nivel de aislamiento usando algo como: IsolationLevel = System.Transactions.IsolationLevel.ReadUnCommitted ... sin embargo, como dice que los datos son relativamente estáticos, todavía estoy adivinando que (a) la consulta que está comparando no es la que realmente se envió, o (b) su DataContext está desactualizado. –

1

Puede usar un DebuggerWriter para verificar el SQL real enviado al servidor.

+0

Gracias, ya lo hice, con el mismo resultado. Es lo que quise decir en la publicación original cuando noté que usé la "propiedad de registro DataContext" para escribir en un archivo. A menos que quisieras decir otra cosa. Si es así, por favor dilucida. –

1
qry.ToList() 

Esta declaración crea y devuelve la lista que desea. Debe asignar el resultado a algo (como una variable local) si desea usar la lista más adelante.

Editar: gracias por la actualización.

sospecho que debe haber algo que no nos estás diciendo que también podría ser un problema, y ​​podría vivir aquí:

Dim db as MyDataContext = MyGetDataContextHelper() 

¿Este método se conectan a la misma base de datos como el que se ha conectado a cuando usaste el estudio sql?

  • Compruebe la propiedad de conexión del contexto de datos.
  • Asegúrese de que la consulta se emite a la base de datos mirándola con el generador de perfiles sql.
  • Emita una consulta muy simple y confirme que devuelve los resultados correctos.
+0

Mi código debería haber leído Retorno qry.ToList(), ya que el fragmento de código es parte de una función que devuelve la Lista. He editado el código para reflejar eso. –

1

Puede sonar tonto, pero siempre es bueno comprobarlo, ¿se está conectando al mismo entorno de base de datos en SSMS que usted es de su aplicación? :)

Cuestiones relacionadas