We recently had an issue where a piece of our code was evaluating the same IEnumerable multiple times. This is generally harmless if the IEnumerable is an array, but problematic if the IEnumerable is an entity framework repository or query set.
Is there a Sonar Cloud alert or monitor that could detect whether a single IEnumerable is evaluated more than once?
Hi Colin ! Thanks for responding. I don’t believe I’m reporting a false positive. In this case, my team did not get a sonar cloud alert.
Instead, what happened is we investigated an issue reported with our website, and we discovered it was due to a single query being evaluated multiple times. I researched the problem and found that some people had used static code analysis tools like resharper or stylecop to detect the problem, and since my company has standardized on SonarCloud, I was curious to know if we can do this same thing in SonarCloud.
The title of my post perhaps should have been “Does SonarCloud have an alert for DotNet code that evaluates a Queryable multiple times?”
Yes, here’s roughly what the code that caused the problem looks like:
var myQueryResult = Context.MyWidgets.Where(q => q.FieldOne == alert.FieldOne && !q.Processed && q.UserId == alert.UserId);
// This triggers the query once, and it is fast, because there is an index intended for this use
foreach (var items in myQueryResult)
{
... do something with alerts ...
}
// The person who wrote this code believed that myQueryResult was an array, and could be re-sorted
// in memory. Because it's still an IQueryable, it triggers a second database query but because of
// the "order by" clause it is nonperformant.
if (someCondition) {
// I would hope that sonar cloud could label this with a code smell: "IQueryable executed multiple times"
var lastItem = myQueryResult.OrderByDescending(a => a.CreatedDate).FirstOrDefault();
if (item) {
... do something with this single item ...
}
}
EDIT: The fix we applied was this:
var myQueryResult = Context.MyWidgets.Where(q => q.FieldOne == alert.FieldOne && !q.Processed && q.UserId == alert.UserId)
.ToList(); // Converting this to a list means it is only executed once
Hi Ted. There’s a Microsoft Analyzer that does exactly what you need: CA1851. Have you tried it on your project? It seems like a fairly new rule (introduced with .NET 7.0).
Thanks! I’ll ask the team whether we have this rule enabled. Is this something I can turn on in SonarCloud, or do I need to seek out an alternative linter for this?
Yes, SonarCloud can use Roslyn rules. And if you want to try it locally, then you can enable it in Visual Studio by setting the Analysis level to Latest All in the .NET analyzers section in the project settings.