Newsgroup: it.comp.dotnet
Titolo: Geneare dinamicamente delle clausole OrderBy

Ciao a tutti,
prendendo spunto da questo post di Raf:
http://blogs.ugidotnet.org/raffaele/archive/2009/04/17/un-po-di-free-style-con-linq-e-gli-expression-tree.aspx
ho creato un'interfaccia che mi genera al volo delle 
Expression<Func<MyEntity, bool>> da sparare in una query LINQ:
var myPredicateBuilder = ...; //la mia interfaccia
var expr = myPredicateBuilder.Create(...); //parametri vari :-)
ISession s = ...; //nhibernate session
var query = s.Query<MyEntity>.Where(expre);
so far, so good. Ora, ho bisogno di generare dinamicamente anche le 
clausole di ordinamento. Supponiamo che la mia entità abbia queste property:
class MyEntity
{
     int Seed {...}
     string Label {...}
     DateTime Stamp {...}
}
se ho la situazione:
IQueryable<MyEntity> q = ...;
q.OrderBy(item => item.Seed);
il compilatore fa type inference e sa che l'argomento dell'OrderBy è una 
Expression<Func<MyEntity, int>>. Volevo perciò creare un metodo:
interface IPredicateBuilder
{
     Expression<Func<MyEntity, TKey>> GetOrderClause(string criteria);
}
che facesse una cosa del tipo:
if (criteria == "Seed") return (item) => item.Seed;
if (criteria == "Label") return (item) => item.Label
...ecc ecc...
Ma il compilatore - giustamente!!! - ha da ridire che non si può 
convertire int a TKey (nel caso di Seed), o string a TKey (nel caso di 
Label), ecc ecc...
Qualche consiglio?
Grazie,
Giulio
-- 

 
http://www.google.com/url?sa=D&q=http://blogs.ugidotnet.org/raffaele/archive/2009/04/17/un-po-di-free-style-con-linq-e-gli-expression-tree.aspx

Ciao Giulio,
La cosa "meno indecente" che mi viene in mente e' convertire tutto a
stringa e quindi ritornare una Expression<Func<MyEntity, string>>:
  if (criteria == "Seed") return (item) => item.Seed.ToString("X8");
  if (criteria == "Label") return (item) => item.Label;
  if (criteria == "Stamp") return (item) => item.Stamp.ToString("s");
(Occhio che il Seed.ToString come l'ho scritto funziona assumendo che
i valori sono tutti non negativi.)
Naturalmente non escludo che esistano approcci migliori, nel qual caso
sono sicuro che qualcuno si fara' sentire... oppure se sei tu a
scovare qualcosa di meglio, facci sapere...
HTH,
-LV

 stringa e quindi ritornare una Expression<Func<MyEntity, string>>:
Io invece ero arrivato a Expression<Func<MyEntity,object>> :-) dopo ore 
e ore di prove e consultazione sul canale #csharp di freenode.
Comunque, anche da un punto di vista teorico non credo che la cosa sia 
percorribile. Alla fine posso "arginare" il problema con una cosa del 
genere:
public interface IOrderingPolicy
{
     IQueryable<MyEntity> ApplyPolicy(string policyName, 
IQueryable<MyEntity> source);
}
La melma da scrivere a mano è ancora tanta, ma almeno è ben arginata in 
un punto. :-)
Ciao,
Giulio
-- 

 un punto. :-)
Per un po' meno di "melma", magari considera che la OrderBy ha un
overload che prende un comparer: ma ci avevo pensato e mi sembra una
strada comunque meno efficiente di quella che ti proponevo...
-LV


P.S. Nonche', ovviamente, molto piu' complessa.
-LV

 strada comunque meno efficiente di quella che ti proponevo...
La strada dell'overload non so quanto sia percorribile, effettivamente. 
Non conosco bene LINQ dal di dentro ma... come fa a usare il comparer in 
maniera efficiente nella generazione di una query SQL? A me l'unico modo 
che viene in mente è generare le entità una per una e applicare il 
comparer...
Una domanda: potresti spiegarmi perché l'approccio basato su stringhe 
dovrebbe funzionare e quello basato su object no? Onestamente non riesco 
a figurarmelo.
Ciao e buon finesettimana,
Giulio
-- 

 a figurarmelo.
E tu potresti spiegarmi perche' a quel proposito dicevi che "Comunque,
anche da un punto di vista teorico non credo che la cosa sia
percorribile"? Ovviamente potrei sbagliarmi, ma continuo a pensare che
la conversione a stringa come ti mostravo in origine sia la soluzione
migliore da *tutti* i punti di vista... per lo meno fra le soluzioni
viste fin'ora.
(Giulio, siamo qui per imparare... in particolare, se non mi dai
feedback opportuno diventa un po' troppo a senso unico.)
-LV

 feedback opportuno diventa un po' troppo a senso unico.)
Effettivamente hai ragione: a volte do troppo per scontato e parto dal 
presupposto che tutti gli altri sappiano tutto. :-)
Scusa ancora,
Giulio
-- 

 presupposto che tutti gli altri sappiano tutto. :-)
Forse dovresti semplicemente rilassarti un po' e leggere meglio le
risposte che ti arrivano...
-LV

 }
Ok, nell'implementazione di ApplyPolicy ci ho messo la "melma" di cui ti 
dicevo prima. :-)
Thanks,
Giulio
-- 

 i valori sono tutti non negativi.)
No way!! Ovviamemente compila, ma poi genera la classica eccezione
"... has no supported translation to SQL".
Bottom line, dopo alcune prove, non so se c'e' (e forse non c'e') un
modo pulito di avere quella logica generata direttamente nell'SQL:
sembrerebbe proprio che l'unica sia risolvere client-side.
-LV