Convertir la expresión LINQ a texto SQL sin contexto DB

.net c# expression-trees linq sql

Pregunta

Ya sea LINQ to SQL o LINQ to Entities ya tienen la capacidad de convertir LINQ en una cadena de texto SQL. Pero quiero que mi aplicación realice la conversión sin usar el contexto db, que a su vez significa una conexión de base de datos activa, que ambos proveedores requieren.

Me gustaría convertir una expresión LINQ en una (s) cadena (s) de SQL equivalente para las cláusulas WHERE y ORDER BY , sin una dependencia de contexto DB, para hacer que la siguiente interfaz de repositorio funcione:

public interface IStore<T> where T : class 
{
     void Add(T item);
     void Remove(T item);
     void Update(T item);
     T FindByID(Guid id);

     //sure could use a LINQ to SQL converter!
     IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
     IEnumerable<T> FindAll();
}

PREGUNTA

Lo que más me interesa es principalmente la expresión transversal y transformación del árbol. ¿Alguien sabe de una biblioteca existente (nuget) que pueda incorporar para usarla en ese contexto personalizado?

Tal como está, ya he creado mi propia herramienta de trabajo "LINQ transformado a texto SQL", similar a este árbol de expresiones al ejemplo de SQL que funciona en mi repositorio anterior. Me permite escribir código como este:

IRepository<Person> repo = new PersonRepository();
var maxWeight = 170;
var results = repo.Find(x => (x.Age > 40 || x.Age < 20) && x.Weight < maxWeight);

Pero mi código y esa muestra son primitivos (y esa muestra se basa en un contexto LINQ to SQL db). Por ejemplo, ninguno maneja la generación de declaraciones "LIKE".

No espero ni necesito una herramienta de generador que maneje cada consulta LINQ concebible. Por ejemplo, no me preocupa el manejo y la generación de uniones o inclusiones. De hecho, con otras ~ 20 horas, mi propio código personalizado puede cubrir todos los casos que me interesan (en su mayoría "WHERE" y "ORDER BY").

Pero al mismo tiempo siento que no debería tener que escribir mi propio código personalizado para hacer esto. Si me quedo atascado escribiendo el mío, todavía estaría interesado si alguien me pudiera indicar clases específicas que pueda reflejar e imitar (NHibernate, EF, etc.). Estoy preguntando sobre clases específicas para echar un vistazo, si las conoce, porque no quiero pasar horas revisando el código de una herramienta masiva solo para encontrar la parte que necesito.

No es que importe, pero si alguien quiere saber por qué no estoy usando simplemente LINQ to SQL o LINQ to Entities ... para mi aplicación específica, prefiero usar una herramienta como Dapper .

CASOS DE USO Ya sea que termine de construir la herramienta yo mismo, o encuentre una biblioteca de terceros, aquí hay razones por las que una "cadena de texto LINQ to SQL" sería útil:

  • El predicado que IRepository.Find en el método IRepository.Find tiene una IRepository.Find y una verificación básica en tiempo de compilación.
  • Mi interfaz IStore propuesta puede implementarse para el acceso a la base de datos o el acceso al servicio web. Para aclarar, si puedo convertir el predicado LINQ "WHERE / ORDER BY" a una cláusula SQL de "WHERE / ORDER BY" entonces ...
    • La cadena SQL podría ser utilizada por Dapper directamente.
    • La cadena SQL, a diferencia de una expresión LINQ, puede enviarse a un servicio WCF para ser utilizada para el acceso directo a la base de datos (que a su vez podría no estar usando Dapper).
    • La cadena SQL podría ser deserializada, con código personalizado , de nuevo en una declaración LINQ por el servicio WCF. Eric Lippert comenta sobre esto .
  • La interfaz de usuario puede usar la mecánica de IQueryable para generar dinámicamente un predicado para dar al repositorio

En resumen, una herramienta de este tipo ayuda a cumplir con la noción de "especificación" o "objeto de consulta" de los repositorios según DDD, y lo hace sin tener que depender de EF o LINQ to SQL.

Respuesta aceptada

Esto es algo que miré brevemente hace bastante tiempo. Es posible que desee consultar http://iqtoolkit.codeplex.com/ y / o http://expressiontree.codeplex.com/ para obtener ideas. Como lo mencionaron otros, la creación del proveedor de consultas Linq está lejos de ser trivial si no limita su alcance al conjunto mínimo de características que realmente necesita.

Si sus objetivos se relacionan con la noción de "especificación" o "objeto de consulta" de los repositorios de acuerdo con DDD, esta puede no ser la mejor dirección a seguir. En lugar de CRUD como las abstracciones relacionadas con la tecnología, puede ser más productivo centrarse en las formas en que se puede expresar el comportamiento del dominio, con un mínimo de dependencias directas en las abstracciones relacionadas con la tecnología. Como Eric Evans discutió recientemente, lamenta el enfoque en los bloques de construcción técnicos, como los repositorios, en sus descripciones iniciales de DDD.


Respuesta popular

Hacer esto correctamente es realmente extremadamente complicado, especialmente si ahora mismo, parece que no sabes mucho acerca de los árboles de expresiones (que es lo que IQueryable usa para representar las consultas).

Pero si realmente desea comenzar (o simplemente tener una idea de cuánto trabajo sería), eche un vistazo a la serie de 17 partes de Matt Warren's Construyendo un proveedor de IQueryable .



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow