Converti espressione LINQ in testo SQL senza contesto DB

.net c# expression-trees linq sql

Domanda

Sia LINQ to SQL o LINQ to Entities hanno già la capacità di convertire LINQ in una stringa di testo SQL. Ma voglio che la mia applicazione effettui la conversione senza utilizzare il contesto db, che a sua volta significa una connessione al database attiva, richiesta da entrambi i provider.

Mi piacerebbe convertire un'espressione LINQ in una stringa SQL equivalente per le clausole WHERE e ORDER BY , senza una dipendenza del contesto DB, per far funzionare la seguente interfaccia del repository:

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();
}

DOMANDA

È principalmente l'espressione tree traversal e transform a cui sono interessato. Qualcuno sa di una libreria esistente (nuget?) Che posso incorporare per essere utilizzata in un contesto così personalizzato?

Come ho già creato il mio strumento "LINQ trasformato in testo SQL", simile a questo albero di espressioni in un esempio SQL che funziona nel mio repository precedente. Mi permette di scrivere codice come questo:

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

Ma il mio codice e quel campione sono primitivi (e il campione stesso si basa su un contesto db LINQ to SQL). Ad esempio, nessuno dei due gestisce la generazione di istruzioni "LIKE".

Non mi aspetto o ho bisogno di uno strumento generatore che gestisca ogni query LINQ concepibile. Ad esempio, non sono preoccupato per la gestione e la generazione di join o include. In effetti, con un altro ~ 20 ore il mio codice personalizzato può coprire tutti i casi che mi interessano (principalmente "WHERE" e "ORDER BY").

Ma allo stesso tempo sento che non dovrei scrivere il mio codice personalizzato per farlo. Se sono bloccato a scrivere il mio, sarei ancora interessato se qualcuno mi indicasse classi specifiche che posso riflettere e imitare (NHibernate, EF, ecc.). Sto chiedendo di classi specifiche da sbirciare, se le conosci, perché non voglio passare ore a setacciare il codice di uno strumento enorme solo per trovare la parte di cui ho bisogno.

Non che sia importante, ma se qualcuno vuole sapere perché non sto semplicemente usando LINQ to SQL o LINQ alle Entità ... per la mia specifica applicazione preferisco semplicemente usare uno strumento come Dapper .

CASI DI UTILIZZO Sia che finisca di costruire lo strumento da solo, sia che trovi una libreria di terze parti, ecco i motivi per cui una "stringa di testo LINQ to SQL" sarebbe utile:

  • Il predicato che IRepository.Find metodo IRepository.Find ha un intellisense e un controllo base in fase di compilazione.
  • La mia interfaccia IStore proposta può essere implementata per l'accesso al DB o l'accesso al servizio web. Per chiarire, se posso convertire il predicato LINQ "WHERE / ORDER BY" in una clausola SQL "WHERE / ORDER BY", allora ...
    • La stringa SQL potrebbe essere utilizzata direttamente da Dapper.
    • La stringa SQL, a differenza di un'espressione LINQ, può essere inviata a un servizio WCF da utilizzare per l'accesso diretto al DB (che a sua volta potrebbe non utilizzare Dapper).
    • La stringa SQL potrebbe essere deserializzata, con codice personalizzato , nuovamente in un'istruzione LINQ dal servizio WCF. Eric Lippert commenta questo .
  • L'interfaccia utente può utilizzare la meccanica IQueryable per generare dinamicamente un predicato da assegnare al repository

In breve, tale strumento aiuta a soddisfare la nozione di "specifica" o "oggetto di query" di repository secondo DDD, e lo fa senza assumere una dipendenza da EF o LINQ a SQL.

Risposta accettata

Questa è una cosa che ho esaminato brevemente un po 'di tempo fa. Si consiglia di dare un'occhiata a http://iqtoolkit.codeplex.com/ e / o http://expressiontree.codeplex.com/ per le idee. Come menzionato da altri, la costruzione del provider di query di Linq è tutt'altro che banale se non si limita l'ambito al set minimo di funzionalità di cui si ha realmente bisogno.

Se i tuoi obiettivi riguardano la nozione di "specifica" o "oggetto di query" di repository secondo DDD, questa potrebbe non essere la direzione migliore da prendere. Invece di CRUD come le astrazioni legate alla tecnologia, può essere più produttivo concentrarsi sui modi in cui il comportamento del dominio può essere espresso, con un minimo di dipendenze dirette sulle astrazioni legate alla tecnologia. Come Eric Evans ha recentemente discusso, si rammarica di concentrarsi sugli elementi tecnici, come i repository, nelle sue descrizioni iniziali di DDD.


Risposta popolare

Fare ciò correttamente è davvero estremamente complicato, specialmente se al momento non sembra che tu sappia molto sugli alberi di espressione (che è quello che IQueryable usa per rappresentare le query).

Ma se vuoi davvero iniziare (o solo avere un'idea di quanto lavoro sarebbe), dai uno sguardo alla serie di 17 parti di Matt Warren Costruire un provider IQueryable .



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché