I have a method;
public List<Task> GetTasksByAssignedTo(Guid contactId)
{
List<Task> tasks = dc.Tasks.Where(x => x.ContactId == contactId).ToList();
return tasks;
}
which returns a list of items. Say I now wanted to specify the sort order I want to return the list in.
So I might sort by Name, DueDate, Completed etc, etc.
How could I include that in the method as a parameter? I don’t want to use a switch statement rather I’d like to use a lambda if possible.
So;
List<Task> list = GetTasksByAssignedTo("guid", ??????);
Or is this the wrong approach.
I think that your approach is the wrong way to use LINQ.
LINQ uses a deferred execution model for a reason. It allows you to chain together a series of operations that get executed only when you tell it to compute the result – often with
.ToList(),.ToArray(),.First()– but you can also force the computation by filtering with aOrderByclause that uses aFunc<T, ?>as its parameter.Now you’re returning a
List<Task>which means that you’ve forced the execution – which is the right thing to do when you’re ready to use the results – but if you then go on to do further operations you are potentially loading many more records into memory than you need to.You could certainly do this:
To make the execution happen in the database you need to change it like this:
But the issue is what if you did this:
Because your
GetTasksByAssignedTobrings records into memory you are doing the join in memory. (Yes, the query is a bit contrived, but the principle is solid though.)It’s often much better to do it in the database.
Here’s how to fix it:
Now the above query won’t execute until you do
query.ToList()and all will happen at the database.But I have an even bigger issue.
You’re hiding a lot of information in the
GetTasksByAssignedTo. Someone using the code doesn’t know that they’re actually getting a list when they read the code and they really don’t know if the actual implementation is doing the right thing. I think, for these kinds of queries, it’s often better to leave it as plain LINQ.Compare these:
The first query,
tasks1isn’t too bad, but it doesn’t tell you what the return type is;The second query,
tasks2does something with sometand the propertyName, but doesn’t tell you what.The third query,
tasks3give you a hint that it is sorting descending, but doesn’t tell you if it’s by the mysteriousNameproperty or something else.The fourth query,
tasks4tells you everything that you need to know – it’s filtering tasks byContactId, reverse ordering the results byName, and finally returning a list.Now, take a look at this query:
I can read that quite easily and see what it is doing. Just imagine what the helper method name would be for this one! Or what insane nesting of helper methods would be required.
The bottom-line is that LINQ is the API for querying.
If you desperately want to create helper methods then use extension methods.
This then allows you to write this:
And that is clear, concise, extensible, composable, re-usable, and you control when execution occurs.