Nei newsgroup ogni tanto si trovano delle domande "stuzzicanti" quella che di recente mi ha incuriosito più di altre è stata "Come faccio a ordinare una query LINQ in base al contenuto di una variabile?" ovvero, è possibile scrivere qualcosa del tipo:
string column = "Country";
var ret = from c in db.Customers orderby column select c;
Il codice compila ma non produce ovviamente il risultato sperato, ecco quindi una serie di possibili alternative che ho verificato con una semplice applicazione che vedete qui sotto:
Prima soluzione: (Quick & Dirty) Mega-switch e creare le expression da passare all'extension method Where con lo svantaggio di dovere prevedere a priori ogni possibile colonna supportata.
MyDbDataContext db=new MyDbDataContext();
db.Log=Console.Out;
Expression<Func<Customer, string>> exp;
switch (txtFieldName.Text)
{
case "country":
exp = c => c.Country;
break;
case "city":
exp = c => c.City;
break;
case "contactname":
exp = c => c.ContactName;
break;
default:
throw new NotImplementedException("Property not yet supported.");
}
dgv.DataSource = db.Customers.OrderBy(exp);
Seconda soluzione: (Back to basics!) creare una query SQL "on the fly" e passarla a ExecuteQuery<T>:
MyDbDataContext db = new MyDbDataContext();
db.Log = Console.Out;
string query = string.Format("SELECT * FROM Customers ORDER BY {0}", txtFieldName.Text);
var ret = db.ExecuteQuery<Customer>(query);
dgv.DataSource = ret.ToArray();
la query in questo caso non può essere direttamente creata via ExecuteQuery<T>.
Terza soluzione: (Coolest!) creare l'espressione dinamicamente:
MyDbDataContext db = new MyDbDataContext();
db.Log = Console.Out;
ParameterExpression pe = Expression.Parameter(typeof(Customer), "c");
MemberExpression mex = Expression.Property(pe, typeof(Customer).GetProperty(txtFieldName.Text));
Expression<Func<Customer, string>> lambda = Expression.Lambda<Func<Customer, string>>(mex, pe);
dgv.DataSource = db.Customers.OrderBy(lambda);
La creazione dell'expression tree dinamicamente offre delle possibilità veramente interessanti e, in alcuni casi, difficilmente raggiungibili con la classica sintassi offera da LINQ.
Altri suggerimenti? (tipo associare alla expression un custom method...)
Expression<Func<Customer, string>> lambda = MyCustomFilter();