I keep coming across the same type of difficulty in several places in my current project.
The simplest instance is as follows:
I have two related entities, Request and RequestAction. Each RequestAction has a status and a timestamp and points back to a Request.
I need to query a collection of Requests based on the status of the most recent related RequestAction.
Example: Get all Requests where the status of the most recent RequestAction is "Open".
Denormalizing the database to make the most recent status a property of the Request entity is not an option.
I need need the same type of filtering in many other places in my application; I keep track of many versions of items for history and auditing, but I usually only want to look at the most recent version of each item.
I can think of two solutions, but neither is particularly appealing.
1) I can write the SQL manually. The raw SQL answer to this problem involves joining the table to itself with an outer join on the timestamp of one instance of the table being larger than the other, then looking for the records where the second table is null, indicating that no larger timestamp could be found. This is how I handeled the scenario in the past. It is efficient in the database as it uses indexes, unlike a subquery with a max in it. However, my development team is being strongly pushed to use entity going forward to talk to the database, so this solution is being strongly discouraged.
2) I can use entity to load all the values into memory and loop through manually in my code to find the values I am looking for. The code would look something like this:
var openRequests = new List<Request>();
var allRequests = context.Requests;
foreach (var request in allRequests)
{
var recentAction = request.RequestActions
.OrderByDescending(c => c.ActionTimestamp)
.First();
if (recentAction.Status == "Open")
{
openRequests.Add(request);
}
}
While this would provide me with the results I want, it is horribly inefficint and a huge waste of resources and execution time. The database I am querying against is very large and iterating through each record is really not feasable.
Is there an efficient way to do this using entity? I find it hard to imagine that I am the only one who has ever needed this type of functionality.