5

Estamos usando EF4 en un sistema bastante grande y ocasionalmente enfrentamos problemas debido a que EF4 no puede convertir ciertas expresiones en SQL. En este momento, debemos hacer algún trabajo de pies (DB/Code) o simplemente aceptar el golpe de rendimiento y permitir que la consulta se ejecute en la memoria.Extendiendo EF4 SQL Generation

Huelga decir que ninguno de estos es ideal y los hacks que a veces hemos tenido que usar reducen la legibilidad/mantenibilidad.

Lo que idealmente nos gustaría es una forma de ampliar las capacidades de generación de SQL del proveedor de EF4 SQL. Obviamente, hay algunas cosas, como las llamadas al método .Net, que siempre tendrán que ser del lado del cliente, pero algunas funcionalidades, como las comparaciones de fechas (por ejemplo, [Agrupar por semanas en Linq a Entities) deberían poderse hacer.

He buscado en Google pero quizás estoy usando una terminología incorrecta, ya que todo lo que obtengo es información sobre las nuevas características de EF4 SQL Generation.

Para un marco tan flexible y extensible, me sorprendería que esto no fuera posible. En mi cabeza, me imagino heredar del proveedor [SQL 2008] y extenderlo para manejar expresiones adicionales/similares en el árbol de expresiones que se le da para convertir a SQL.

Cualquier ayuda/sugerencias apreciadas.

Estamos utilizando VS2010 Ultimate, .Net 4 (perfil no cliente) y EF4. La aplicación se encuentra en ASP.Net y se ejecuta en un entorno de 64 bits en caso de que haga la diferencia.

Actualización: En respuesta a algunas solicitudes de aclaración;

Estamos utilizando un enfoque de primer código y tenemos una aplicación de consola que crea la base de datos y rellena algunas tablas de referencia.

Preferiría mantenerme alejado de los procesos almacenados a menos que también puedan generarse de una manera similar: en la actualidad, se generan nuevas versiones de la base de datos según sea necesario y un proceso separado migra/sincroniza datos. todo que actualmente hacemos con respecto a la base de datos usa entidades. Admito que no puedo dar una buena razón, pero ejecutar scripts SQL para generar procs almacenados parece estar mal en este escenario. Pero corrígeme si me equivoco.

Con respecto a un escenario específico, me temo que no puedo dar uno de nuestro código sin pasar por un largo ejercicio de burocracia - El link mentioned above es un buen ejemplo del tipo de cosas que estamos tratando de realizar. En este ejemplo, la implementación de un mecanismo que permita la aritmética de fechas:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear(); 
var userTimes = from t in context.TrackedTimes 
       group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days/7} into ut 
       select new 
       { 
        UserName = ut.Key.UserName, 
        WeekNumber = ut.Key.WeekNumber, 
        Minutes = ut.Sum(t => t.Minutes) 
       }; 

puedo ver una manera que esto podría lograrse mediante SQL solos pero no cómo hacerlo usando LINQ a Entidades (del lado del servidor).

+0

Es difícil responder a una pregunta tan abstracta. ¿Qué estás tratando de apoyar exactamente? Hay * muchas * formas de hacer esto (EdmFunctions, almacenar consultas, ejecutar SQL literal, etc.). –

+0

Es cierto: he ampliado la pregunta para incluir un ejemplo. Espero que esto esté más claro? – Basic

Respuesta

9

recomendaría primero mirando EntityFunctions (genérico) o SqlFunctions (sólo SQL Server), que proporcionan una gran cantidad de funcionalidad de base de datos integrada dentro de una consulta LINQ normal a Entidades. Si eso no es suficiente, puede usar EdmFunctionAttribute para mapear una función de base de datos integrada o un procedimiento almacenado definido por el usuario. Una tercera opción es intentar que funcione como una consulta Entity SQL.

La última solución que sugirió (escribir un proveedor de EF) es bastante pesada. Es posible escribir un proveedor de EF que envuelva el proveedor de SQL existente, pero tendría que cambiar algunos de los árboles de expresión a Entity SQL como mínimo. Se han lanzado envolturas de proveedores de EF muy simples en MSDN Code. Sin embargo, lo trataría como último recurso.

+0

Gracias por los enlaces muy útiles. Voy a necesitar leer un poco y responderte – Basic

+0

Fantástico, gracias. Tenemos varias opciones a partir de ahí que probablemente mezclaremos y uniremos. – Basic

1

La conversión de sus consultas LINQ basadas en .NET a SQL es manejada por el proveedor LINQ To Entities. No creo que el proceso central de traducción/compilación, que es extremadamente complejo, sea extensible. Tendría que escribir su propio proveedor desde cero.

Todavía tengo que encontrarme con cualquier consulta que pueda representarse en SQL y que no pueda expresarse en LINQ. Si tiene una consulta que es difícil de escribir como una consulta LINQ, ¿ha considerado utilizar procedimientos almacenados? Ayudaría si pudiera proporcionar algunos ejemplos de las consultas que no se convertirán.

ACTUALIZACIÓN:

Otra opción es crear métodos de extensión avanzados que utilizan las expresiones hechas a medida para formar la consulta. Aquí es un buen ejemplo que simula la función contiene() para ejecutar "donde en" consultas del tipo:

'Contains()' workaround using Linq to Entities?

+0

Gracias por la respuesta. El enlace para Contiene() es muy interesante, pero no es exactamente lo que estamos buscando. Ya contamos con métodos de extensión que agregan métodos de And/Or a Expressions.Expression (Of Func (Of T, Boolean) para que los árboles de expresiones se fusionen según corresponda, lo cual es muy útil para combinar múltiples consultas de diferentes niveles de la aplicación (por ejemplo, para agregar restricciones de seguridad). Pero como no veo una manera de modificar las consultas para hacer (por ejemplo, resta de fecha/división de días) usando LINQ, ¿no veo cómo puedo aplicar esta técnica? – Basic

+0

En respuesta a la primera parte de su respuesta, parece ser exactamente lo que estoy tratando de hacer. Estaba empezando a sospechar que no era extensible ya que no he encontrado ninguna información en otro lugar. Ciertamente no podía escribir mi propio proveedor desde cero, así que puede ser una idea sin salida. – Basic

+0

CAST (DateTimeOffset como DateTime) <<<<<< Mucha suerte haciendo eso en Linq-To-Entities. No se puede hacer. Algo tan increíblemente simple como conseguir la parte DateTime de DateTimeOffset es imposible en linq-to-entities, por lo que puede ni siquiera filtra una columna DateTimeOffset por una fecha y hora local, lo que frustra el propósito total de la misma. – Triynko