views:

235

answers:

1

Consider this class:

public class Column<T>
{
    public string Header { get; set; }
    public Func<T, string> ValueExpression { get; set; }
}

used like this:

var columns = new List<Column<Employee>>
              {
                  new Column<Employee> {Header = "Employee Id", ValueExpression = e => e.EmployeeID.ToString()},
                  new Column<Employee> {Header = "Name", ValueExpression = e => e.FirstName + " " + e.LastName},
                  new Column<Employee> {Header = "Employee Birthday Year", ValueExpression = e => e.BirthDate.HasValue ? e.BirthDate.Value.Year.ToString() : ""},
                  new Column<Employee> { Header = "test", ValueExpression = e => e.Address}
              }

I would like to do a .Select() on an IQueryable to make it only retrieve the needed fields from the database.

So I want to do something like this:

var expressions = columns.Select(c => c.ValueExpression).Combine();
IQueryable<Employee> employees = EmployeeRepository.GetEmployees();
employees = employees.Select(expressions);

Only "Combine()" obviously doesn't exist.. :-)

+6  A: 
public static Func<T, U[]> Combine<T, U>(this Func<T, U>[] functions) {
    return t => functions.Select(fun => fun(t)).ToArray();
}

I'd declare that for generic IEnumerable<Func<T, U>> instead of array:

public static Func<T, IEnumerable<U>> Combine<T, U>(this IEnumerable<Func<T, U>> functions)
{
    return t => functions.Select(fun => fun(t));
}

As mentioned in comments, this is not likely to work directly with LINQ to SQL. However, you could grab LINQ to SQL results by doing a .AsEnumerable() and process the rest on client side.

Mehrdad Afshari
A big kiss for you if this solves my problem. Will give it a shot :-)
Thomas Stock
@Mehrdad: Hopefully he will accept the answer as well. :)
Andrew Hare
This answers the question in the title. So +1. Does not solve the "from the database" problem in the body of the question.
David B
That's what I'm afraid of while interpreting this piece of code. I can get execute the expressions on the IQueryably myself, but I see in SQL profiler that all fields from Employees table are retrieved from the DB.
Thomas Stock
@Andrew: LOL! It's the theme these days. I have plenty of answers with "Thank you. It solved my problem." but the user didn't know he should click that checkmark!
Mehrdad Afshari
@Thomas Stock: It's not really possible to do that with Func<T, U> as it's not an expression tree but a delegate compiled to IL. To be able to run that on the DB, you'd have to resort to storing expressions themselves as data (Expression<Func<T,U>>).
Mehrdad Afshari
Comment on your edit: Yeah and I had this working by executing the expressions after converting to Enumerable. But since this code is for a reuseable grid, I want the executed SQL to be as effective as possible.
Thomas Stock
@ Mehrdad: I don't understand your last comment. I've been looking into that Expression stuff but it's still very unclear to me.Do you think I could achieve my goal with Expression? If so, I'll look further into it.
Thomas Stock
My answer on this question http://stackoverflow.com/questions/767733/converting-a-net-funct-to-a-net-expressionfunct/767740#767740 explains the fundamental difference.
Mehrdad Afshari
Otherwise I'll resort to Dynamic Linq with which this might be possible too.
Thomas Stock
I guess for a reusable grid, dynamic LINQ might be your best bet. Manipulating expressions will work great but it requires plenty of code and understanding System.Linq.Expressions namespace. I don't think it provides much benefits. Dynamic LINQ is more flexible.
Mehrdad Afshari
Thanks for the explanation and effort. I'll mark your answer as accepted tomorow if nobody else can provide a solution in the mean while. The kiss will have to wait :-)
Thomas Stock