2008-11-27 57 views
8

¿Alguien sabe de una lista definitiva de limitaciones de consultas de LINQ a SQL que no están atrapadas en tiempo de compilación, junto con (cuando sea posible) soluciones para las limitaciones?"No se pueden llamar los métodos en DateTime" y otras limitaciones

La lista que tenemos hasta ahora es:

  • métodos de llamada tales como .Date en DateTime
    • ninguna solución encontrados
  • string.IsNullOrEmpty
    • sencillo, basta con utilizar == "" inst ead
  • .Last()
    • utilizamos .OrderByDescending(x => x.WhateverProperty).First()
+1

El problema con esta lista es que es un poco como demostrar que es negativo. La lista de cosas que no puedes hacer es infinita, la lista de cosas que * puedes * hacer es mucho más corta. –

+0

Dado que esto se aproxima a "debido" ... ¿hay algo excepcional? ¿Qué más información necesitarías? –

+0

No me importa admitir que me siento un poco engañado solo obteniendo mitad de recompensa por esto ... ¿qué más querías? –

Respuesta

21

Básicamente, esa lista es enorme ... es todo lo que fuera de la relativamente small set of things that are handled. Desafortunadamente, el Law Of Leaky Abstractions entra en acción, y cada proveedor tiene diferentes respuestas ...

LINQ-to-Objects hará cualquier cosa (casi), ya que es delegados; LINQ-to-SQL y Entity Framework tienen diferentes conjuntos de soporte.

En general, he tenido bastante éxito usando las propiedades DateTime, etc., pero en realidad, tendrá que asegurarse de que las expresiones de consulta estén cubiertas por pruebas unitarias, de modo que si alguna vez cambia proveedores (o el proveedor se actualiza) usted sabe que todo sigue funcionando.

Supongo que una vista es pensar en términos de TSQL; no hay BOTTOM n, pero hay un TOP 1 (re el OrderByDescending); En términos de string.IsNullOrEmpty, puede ser bastante literal: foo.Bar == null || foo.Bar == ""; y con DateTime.Date probablemente puedas hacer bastante con DATEPART/los diversos componentes.

Otra opción con LINQ to SQL es encapsular la lógica de una UDF - por lo que podría escribir una UDF que toma un datetime y devuelve un datetime, y exponer que a través de la dbml en la técnica de contexto. A continuación, puede utilizar eso en sus consultas:

where ctx.Date(foo.SomeDate) == DateTime.Today 

Este enfoque, sin embargo, no significa necesariamente que un buen uso de índices.


Actualización:

  • Las traducciones método admitido etc son here.
  • Las operaciones de consulta admitidas, etc. son here.

Para los detalles morbosos completos, se puede ver en System.Data.Linq.SqlClient.PostBindDotNetConverter+Visitor en el reflector - en particular, los métodos Translate...; algunas funciones string se manejan por separado. Así que no es una gran selección de , pero este es un detalle de implementación.

0

Tuve exactamente este problema con DateTimes, y descubrí que actualmente la siguiente solución funciona, pero me doy cuenta de que con conjuntos de resultados más grandes, podría ser un problema ya que el procesamiento ahora está en mi aplicación en lugar de en la base de datos:

BlogPosts post = (from blogs in blogPosts 
      where blogs.PostPath == path 
      select blogs) 
      .ToList() 
      .Where(blogs => blogs.Published.Date == publishedDate.Date) 
      .SingleOrDefault(); 

Nota del ".ToList()" en el medio - esto arroja a un IEnumerable normal y me permite utilizar las propiedades habituales que cabe esperar.

Una cosa que todavía me confunde un poco sin embargo, es el hecho de que esto es legal en EF:

BlogPosts posts = from blogs in blogPosts 
      where !blogs.IsDraft 
      && blogs.Published.Year == year 
      && blogs.Published.Month == month 
      orderby blogs.Published descending 
      select blogs 

Por lo tanto, puedo llamar ".Año" o ".Month" en un DateTime, pero no " .Fecha "- Supongo que se trata de tipos.

+0

En cuanto al rendimiento, probablemente obtendrías una consulta mucho más rápida al calcular dos valores delimitadores de fecha y hora que contienen el mes, en lugar de utilizar el equivalente de funciones DATEPART (MM, dt) en tu consulta. –

+0

Saludos, voy a probar eso también. –

+0

. AsEnumerable() sería menos invasivo (sin almacenamiento en búfer); De cualquier manera, pierdes compotabilidad. –

1

LINQ es el idioma. LINQ-to-SQL compila tu comando LINQ en una consulta SQL. Por lo tanto, está limitado por las limitaciones normales de la sintaxis TSQL, o más bien los elementos que se pueden convertir fácilmente en ella.

Como han dicho otros, las listas de lo que no se puede hacer serían enormes. Es una lista mucho más pequeña de lo que puedes hacer. Una regla general es tratar de determinar cómo la función que desea usar se convertiría a TSQL. Si tiene muchos problemas para resolverlo, entonces no use esa función (o al menos pruébela primero).

Pero hay una solución fácil de usar para los comandos LINQ que no están en LINQ-to-SQL. Separe las porciones de LINQ puro de su código de las porciones LINQ-a-SQL. En otras palabras, realice el LINQ-to-SQL para extraer los datos (con cualquier función que necesite que esté disponible en LINQ-to_SQL), con el comando para colocarlo en un objeto (ToEnumerable, ToList u otros similares). Esto ejecuta la consulta y extrae los datos locales. Ahora está disponible para la sintaxis LINQ completa.

0

La respuesta de Marc Gravell es exhaustivamente correcta.

Solo quería agregar este detalle para Date Logic (y comparaciones de cadenas). Como está utilizando LinqToSql, puede aprovechar el SqlMethods para hacer las cosas que está acostumbrado a hacer en la base de datos.

Cuestiones relacionadas