Reputation: 6386
I'm trying to search in an IEnumerable
for a specific record (using a predicate). If that record doesn't exist, I want to return the first record. If that also doesn't exist, I just want null
.
I'm currently using
var category = categories.FirstOrDefault(
c => c.Category == "C") ??
category.FirstOrDefault();
ReSharper gives me a warning (Possible multiple enumeration of IEnumerable). The warning tells me my sql statement might be executed twice. Once to try and find a "C" category, and once more to get the first record. The warning will go away if I first convert categories to a List by using categories.ToList()
. But if categories contains a lot of records, that could be slow.
Is there a more elegant way to do this? Or should I just ignore the warning?
Upvotes: 3
Views: 4597
Reputation: 2233
The ReSharper warning is more a message saying "Think about what you are doing", not a "You are doing it wrong".
Your solution is not that bad, but it all depends on the situation.
In production, how often will the category not exist? Is it a rare case, then leave your code as is. Another thing to consider is the frequency in which this code is executed. Is it once a day, or ten times per second? Is it more like the first? Leave it as is.
Otherwise, micro optimization can be of benefit. A solution like Seyana might work or you could for instance rewrite the queries to be a union(), with a Take(1), so only one query will be send to SQL Server; but that doesn't mean both queries won't be executed by the database engine.
Profiling will give your answer to which solution is the fastest or uses the least amount of resources.
Upvotes: 1
Reputation: 17064
If you have a column in your categories table that is sequential, you could do something like this:
var category = categories.Where(c => c.SomeSequentialId == 1 || c.Category == "C")
.OrderByDescending(c => c.SomeSequentialId)
.FirstOrDefault();
Upvotes: 1
Reputation: 10538
If you are really worried about performance, FirstOrDefault is O(n). Your second query is only going to execute if the first is null. You could try using .Any(predicate). First() lends itself to try { } catch which might be better for your situation.
You don't really need to worry about performance optimization until it becomes an issue, though.
Upvotes: 1