EFCoreLint 0.2.0

dotnet add package EFCoreLint --version 0.2.0
                    
NuGet\Install-Package EFCoreLint -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EFCoreLint" Version="0.2.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EFCoreLint" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="EFCoreLint">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EFCoreLint --version 0.2.0
                    
#r "nuget: EFCoreLint, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EFCoreLint@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EFCoreLint&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=EFCoreLint&version=0.2.0
                    
Install as a Cake Tool

EFCoreLint

CI NuGet NuGet Downloads

Roslyn analyzers that catch common Entity Framework Core anti-patterns at compile time — before they reach production.

Installation

dotnet add package EFCoreLint

No configuration required. Diagnostics appear automatically in your IDE and in dotnet build output.

Diagnostics

ID Severity Description
EFLINT001 Warning Client-side filtering after materialization
EFLINT003 Info Read-only query missing AsNoTracking
EFLINT005 Warning EF Core async method called without await
EFLINT006 Warning Count() used for existence check instead of Any()
EFLINT007 Warning Blocking on EF Core async operation with .Result or .Wait()

All severities can be overridden per-project via .editorconfig:

[*.cs]
dotnet_diagnostic.EFLINT001.severity = error
dotnet_diagnostic.EFLINT003.severity = none

EFLINT001: Client-side filtering

Calling ToList() or ToArray() before Where() pulls every row into memory and filters client-side. Move the filter before materialization so the database does the work.

// ❌ Warning EFLINT001 — loads all Products into memory first
var expensive = db.Products.ToList().Where(p => p.Price > 100);

// ✅ Fixed — WHERE clause executes on the database
var expensive = db.Products.Where(p => p.Price > 100).ToList();

A code fix is available: applying it rewrites the call order automatically.


EFLINT003: Missing AsNoTracking

EF Core tracks every queried entity by default, allocating a change-tracking snapshot even when you never call SaveChanges. For read-only queries, AsNoTracking() skips this overhead.

// ℹ️ Info EFLINT003 — change-tracking snapshot allocated unnecessarily
var products = db.Products.Where(p => p.IsActive).ToList();

// ✅ Fixed — no tracking overhead
var products = db.Products.AsNoTracking().Where(p => p.IsActive).ToList();

A code fix is available: it inserts .AsNoTracking() before the materializing call.

The diagnostic is suppressed when SaveChanges or SaveChangesAsync is called in the same method, because tracking is needed there.


EFLINT005: Missing await on async query

EF Core async methods (ToListAsync, FirstOrDefaultAsync, SaveChangesAsync, etc.) return a Task<T> that must be awaited to actually execute the query. Without await, the operation is silently discarded.

// ❌ Warning EFLINT005 — query never executes, result discarded
db.Products.ToListAsync();

// ✅ Fixed
var products = await db.Products.ToListAsync();

A code fix is available when the containing method is already async: it adds the await keyword.



EFLINT006: Use Any() instead of Count()

Calling Count() and comparing against 0 or 1 to check existence issues a COUNT(*) query that scans every matching row. Any() translates to EXISTS, which stops at the first match.

// ❌ Warning EFLINT006 — COUNT(*) scans all matching rows
if (db.Orders.Where(o => o.IsOpen).Count() > 0) { }

// ✅ Fixed — EXISTS short-circuits on the first match
if (db.Orders.Where(o => o.IsOpen).Any()) { }

Detected patterns: Count() > 0, Count() != 0, Count() >= 1, Count() == 0, Count() < 1, and their flipped equivalents. A code fix is available for all patterns, including Count(predicate)Any(predicate).


EFLINT007: Blocking on async operation

Calling .Result, .Wait(), or .GetAwaiter().GetResult() on a Task returned by an EF Core async method blocks the calling thread and can deadlock in ASP.NET Core applications.

// ❌ Warning EFLINT007 — blocks the thread, risks deadlock
var products = db.Products.ToListAsync().Result;

// ✅ Fixed — asynchronous, no deadlock risk
var products = await db.Products.ToListAsync();

A code fix is available when the containing method is already async: it replaces the blocking call with await.


Suppressing a diagnostic

// In code
#pragma warning disable EFLINT001
var list = db.Products.ToList().Where(p => p.IsActive);
#pragma warning restore EFLINT001

// Or project-wide in .editorconfig
[*.cs]
dotnet_diagnostic.EFLINT001.severity = none

Contributing

Issues and pull requests welcome. Open an issue to discuss a bug or new diagnostic before submitting a PR.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 88 5/26/2026
0.1.0 92 5/22/2026