You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CMTK0009: a Func or a method group passed to FirstOrNone, SingleOrNone or FirstOrError on a query reads every row #129
FirstOrNone, SingleOrNone and FirstOrError on an IQueryable<T> bind to the query's overload only when the condition is a lambda written at the call. A Func<T, bool> held in a variable, or a method group, binds to the IEnumerable<T> overload: EF reads every row and the condition runs in memory, with no warning. QueryOptionTests.A_Func_or_a_method_group_reads_every_row_and_runs_the_condition_in_memory pins this, and its summary says "No analyzer tells it yet". The roadmap lists it under "Gaps, in any 2.x".
Proposal
CMTK0009, a Warning, reports such a call: the receiver's type is an IQueryable<T> and the chosen overload is the sequence one, because the argument is a delegate rather than an expression. A Warning may learn in a minor version (decision 34). CMTK0009's title speaks of a call that returns a default instance, so this case gets its own message, naming the overload it fell to and the row read it causes. LastOrNone and LastOrError given a delegate on a query read every row the same way and are reported too (found by variant analysis). No code fix: see the comment below.
Done when
The analyzer reports a Func variable, a field, a method group and a delegate-returning call, and stays silent for a lambda at the call, an Expression<Func<T, bool>> variable, and a sequence that is not a query; the receiver shapes come from the variant catalogues.
A code fix is considered and either added or ruled out in the issue.
The Analyzers README's CMTK0009 section and the EF README say so, and the test's summary no longer says no analyzer tells it.
Code fix: ruled out. CMTK0009's query condition ships without one, because no mechanical rewrite is correct:
A Func variable, field, property or a call that returns one has its body somewhere else, often built at run time. Making it an expression means changing its declaration and every other use, which is the author's call.
A method group could be wrapped as x => IsGamma(x). That binds to the query's overload, but the provider then has to translate a call to the application's method. EF Core can't, so a silent full read becomes an exception when the query runs.
AsEnumerable() before the call is the one rewrite that keeps behaviour. It only makes the full read explicit and silences the warning. Offering it from the light bulb would make the wrong answer the easiest one.
The Analyzers README's CMTK0009 section says there is no fix and why, and names AsEnumerable() as the way to read every row on purpose.
Scope note: by variant analysis, the rule also reports LastOrNone and LastOrError given a delegate on a query. Their query overloads refuse to compile with a lambda ([Obsolete(error: true)]), but a delegate binds to the sequence overload and reads every row the same way. Their message suggests ordering the query the other way and taking the first.
Activity
CaffeinatedCoder commentedon Oct 29, 2026
Code fix: ruled out. CMTK0009's query condition ships without one, because no mechanical rewrite is correct:
Funcvariable, field, property or a call that returns one has its body somewhere else, often built at run time. Making it an expression means changing its declaration and every other use, which is the author's call.x => IsGamma(x). That binds to the query's overload, but the provider then has to translate a call to the application's method. EF Core can't, so a silent full read becomes an exception when the query runs.AsEnumerable()before the call is the one rewrite that keeps behaviour. It only makes the full read explicit and silences the warning. Offering it from the light bulb would make the wrong answer the easiest one.The Analyzers README's CMTK0009 section says there is no fix and why, and names
AsEnumerable()as the way to read every row on purpose.Scope note: by variant analysis, the rule also reports
LastOrNoneandLastOrErrorgiven a delegate on a query. Their query overloads refuse to compile with a lambda ([Obsolete(error: true)]), but a delegate binds to the sequence overload and reads every row the same way. Their message suggests ordering the query the other way and taking the first.CaffeinatedCoder commentedon Oct 29, 2026
Done in #137, merged into
release/2.3.0(4b4f0c6). No code fix, as the comment above says.