LinqContraband 5.8.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package LinqContraband --version 5.8.1
                    
NuGet\Install-Package LinqContraband -Version 5.8.1
                    
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="LinqContraband" Version="5.8.1">
  <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="LinqContraband" Version="5.8.1" />
                    
Directory.Packages.props
<PackageReference Include="LinqContraband">
  <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 LinqContraband --version 5.8.1
                    
#r "nuget: LinqContraband, 5.8.1"
                    
#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 LinqContraband@5.8.1
                    
#: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=LinqContraband&version=5.8.1
                    
Install as a Cake Addin
#tool nuget:?package=LinqContraband&version=5.8.1
                    
Install as a Cake Tool

LinqContraband

<div align="center">

LinqContraband icon — EF Core LINQ performance Roslyn analyzer

Stop Smuggling Bad Queries into Production

NuGet Downloads License: MIT Build Coverage

</div>

Compile-time EF Core LINQ performance analyzer for .NET — a high-signal Roslyn analyzer that catches N+1 queries, client-side evaluation, premature materialization, sync-over-async, missing AsNoTracking, raw SQL injection risks, and other DbContext query issues in the editor and CI—not production.

The problem

Entity Framework Core and LINQ compile cleanly even when the query shape will hurt production. An N+1 Find inside a loop, ToList() before Where, a local method that forces client-side evaluation, sync-over-async on DbContext, or FromSqlRaw($"...") only fail under load, at 3 AM, or as a security incident.

Runtime profilers and code review miss what static analysis can prove from your IQueryable chains and EF Core API usage.

What it catches

LinqContraband reports proven EF Core LINQ and DbContext pitfalls early:

  • N+1 database execution inside loops (Find, materializers, explicit load)
  • premature materialization (ToList/AsEnumerable before filters)
  • client-side evaluation risk from non-translatable local methods
  • sync-over-async EF Core calls in async methods
  • missing or misused AsNoTracking (tracking tax, silent writes, mixed modes)
  • Cartesian explosion and missing/excessive Include paths
  • SaveChanges inside loops and nested SaveChanges
  • raw SQL injection patterns (FromSqlRaw / ExecuteSqlRaw interpolation)
  • DbContext lifetime and concurrent same-context operations
  • unbounded materialization, projection waste, and pagination without OrderBy

When the analyzer cannot prove an EF-backed query shape statically, it stays quiet. High-signal feedback, not noisy guesses.

Install

dotnet add package LinqContraband

That adds the latest release. To edit the project file by hand instead, use the version shown on the NuGet badge:

<PackageReference Include="LinqContraband" Version="x.y.z" PrivateAssets="all" />

No runtime dependency is added to your app. LinqContraband runs as a Roslyn analyzer during build and in supported IDEs (Visual Studio, Rider, VS Code / C# Dev Kit) and CI.

Install only from NuGet or from this repository. LinqContraband is not distributed as a standalone ZIP installer or executable; treat third-party ZIP downloads as untrusted.

A taste

// LC002: ToList() pulls every order into memory, then filters in C#.
var slow = db.Orders.ToList().Where(o => o.DueDate < today);

// Fix (offered as a code fix): filter in SQL, then materialize.
var fast = db.Orders.Where(o => o.DueDate < today).ToList();
// LC007: one database round trip per customer (N+1).
foreach (var id in customerIds)
    customers.Add(db.Customers.Find(id));

// Fix: one query for the whole set.
customers = db.Customers.Where(c => customerIds.Contains(c.Id)).ToList();

Every diagnostic's help link in your IDE opens the rule's page, which shows the problem, the fix, and the cases the rule deliberately leaves alone.

See it work

Product-flow diagrams from real sample diagnostics and shipped LC message formats:

1. Build / IDE diagnostics (EF Core LINQ)

LinqContraband Roslyn analyzer warnings for EF Core LINQ performance — LC001 client-side evaluation, LC002 premature materialization, LC007 N+1, LC018 FromSqlRaw SQL injection

2. Before / after code fix (premature materialization)

Before and after: EF Core ToList before Where fixed to filter then materialize with LC002 premature materialization code fix

3. Product loop — analyzer in IDE and CI

LinqContraband product loop: Roslyn analyzer build diagnostics for DbContext and IQueryable in the IDE and ContinuousIntegrationBuild CI

30-second path

  1. Reference the package with PrivateAssets="all".
  2. Keep writing EF Core LINQ as usual (DbSet, IQueryable, Include, SaveChanges).
  3. Build in the IDE or with ContinuousIntegrationBuild=true on the command line so analyzers run.
  4. Fix any LC00x warnings (many have code fixes).
  5. Optionally promote critical rules to error in .editorconfig (see Configuration below).

Feature snapshot

Area What LinqContraband does
N+1 queries Flags database execution inside loops and SaveChanges-in-loop write amplification.
Materialization Catches premature ToList/AsEnumerable and redundant second materializers.
Translation Reports local methods and non-translatable string/date patterns that risk client-side evaluation.
Tracking Guides AsNoTracking, silent-write, and mixed tracking-mode hazards.
Loading Detects Cartesian explosion, missing Include, deep ThenInclude, excessive eager loading.
Async Sync-over-async, missing CancellationToken, async stream buffering, concurrent DbContext use.
Raw SQL Interpolated FromSqlRaw/ExecuteSqlRaw and constructed SQL string risks.
Modeling Missing primary keys and explicit foreign-key properties when statically provable.

Compatibility

  • .NET / Roslyn hosts: Visual Studio, Rider, VS Code (C# Dev Kit), and dotnet build / CI
  • EF Core: Modern Entity Framework Core versions used with C# IQueryable / DbContext APIs
  • Package kind: Development dependency analyzer (PrivateAssets="all"); no app runtime package

Rules

48 rules, 31 with automatic code fixes. Each rule links to its full page: what it flags, why it matters, how to fix it, and where it deliberately stays quiet.

Rule What it catches Default severity Code fix
LC001 Client-side evaluation risk: Local method usage in IQueryable Warning Yes
LC002 Premature query continuation after materialization Warning Yes
LC003 Prefer Any() over Count() existence checks Warning Yes
LC004 Deferred Execution Leak: IQueryable passed as IEnumerable Warning Yes
LC005 Multiple OrderBy calls Warning Yes
LC006 Cartesian Explosion Risk: Multiple Collection Includes Warning Yes
LC007 N+1 Problem: Database execution inside loop Warning Yes
LC008 Sync-over-Async: Synchronous EF Core method in Async context Warning Yes
LC009 Performance: Missing AsNoTracking() in Read-Only path Info Yes
LC010 N+1 Write Problem: SaveChanges inside loop Warning Yes
LC011 Design: Entity missing Primary Key Warning Yes
LC012 Optimize: Use ExecuteDelete() instead of RemoveRange() Warning Yes
LC013 Disposed Context Query Warning Manual
LC014 Avoid String.ToLower() or ToUpper() in LINQ queries Warning Manual
LC015 Deterministic Pagination: OrderBy required before Skip/Take Warning Yes
LC016 Avoid DateTime.Now/UtcNow in LINQ queries Warning Yes
LC017 Performance: Consider using Select() projection Info Yes
LC018 Avoid FromSqlRaw with interpolated strings Warning Yes
LC019 Conditional Include Expression Warning Manual
LC020 Avoid untranslatable string comparison overloads Warning Yes
LC021 Avoid IgnoreQueryFilters Warning Yes
LC022 Nested collection materialization inside projection Info Yes
LC023 Use Find/FindAsync for primary key lookups Info Yes
LC024 GroupBy with Non-Translatable Projection Warning Manual
LC025 Avoid AsNoTracking with Update/Remove Warning Yes
LC026 Missing CancellationToken in async call Info Yes
LC027 Missing Explicit Foreign Key Property Info Yes
LC028 Deep ThenInclude Chain Warning Manual
LC029 Redundant identity Select Info Yes
LC030 Potential DbContext lifetime mismatch Info Manual
LC031 Unbounded Query Materialization Info Manual
LC032 Use ExecuteUpdate for provable bulk scalar updates Info Yes
LC033 Use FrozenSet for provably read-only membership caches Info Yes
LC034 Avoid ExecuteSqlRaw with interpolated strings Warning Yes
LC035 Missing Where before bulk execute Info Manual
LC036 DbContext captured by thread work item Warning Manual
LC037 Avoid constructed raw SQL strings Warning Manual
LC038 Avoid excessive eager loading Info Manual
LC039 Avoid repeated SaveChanges on the same context Info Manual
LC040 Avoid mixing tracking modes on the same context Info Manual
LC041 Single entity query over-fetches one consumed property Info Yes
LC042 Complex query should be tagged Info Manual
LC043 Prefer await foreach over buffering async streams Info Yes
LC044 AsNoTracking query mutated then SaveChanges — silent data loss Warning Manual
LC045 Missing Include: navigation accessed on materialized entity Warning Yes
LC046 Concurrent EF Core operations on the same DbContext Warning Manual
LC047 ExecuteDelete bypasses the tracked delete pipeline Warning Yes
LC048 Tracked update can overwrite a concurrent change Warning Manual

Browse the same rules grouped by failure mode in the rule catalog, or start from a topic guide:

Configuration

Set any rule's severity in .editorconfig:

[*.cs]
dotnet_diagnostic.LC001.severity = error
dotnet_diagnostic.LC002.severity = error
dotnet_diagnostic.LC003.severity = warning

# Optional rule-specific thresholds
dotnet_code_quality.LC038.include_threshold = 4
dotnet_code_quality.LC042.query_operator_threshold = 3

Advisory rules default to Info, so they show up as hints without drowning out the higher-confidence warnings.

Run it in CI

LinqContraband runs inside the normal dotnet build, so a CI job needs no database, service container, or extra tool:

- run: dotnet restore
- run: dotnet build --configuration Release --no-restore

Promote the rules you want to block pull requests to error in .editorconfig. The CI guide covers a gradual rollout.

Contributing

Found a new way to smuggle bad queries? Open an issue or send a pull request. The contributing guide explains how to add or change a rule.

License: MIT

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
5.13.0 0 9/25/2026
5.12.0 0 9/24/2026
5.11.0 0 9/24/2026
5.10.0 82 9/23/2026
5.8.1 96 9/22/2026
5.8.0 1,520 9/10/2026
5.7.65 9,042 8/17/2026
5.7.64 116 8/17/2026
5.7.63 107 8/17/2026
5.7.62 114 8/17/2026
5.7.61 111 8/16/2026
5.7.60 111 8/16/2026
5.7.59 122 8/13/2026
5.7.58 110 8/10/2026
5.7.57 113 8/10/2026
5.7.56 113 8/10/2026
5.7.55 117 8/10/2026
5.7.54 110 8/10/2026
5.7.53 114 8/9/2026
5.7.52 102 8/9/2026
Loading failed

Analyzers no longer crash in the IDE (AD0001) when the DbContext, entity configuration, or a called helper lives in a referenced project: LC047 (and with it the LC012 tracked-delete gate) crashed at compilation start, and LC004, LC045, LC046, and LC048 had the same latent crash. LC044 now reports lost AsNoTracking mutations in async helpers completed through Task.WhenAll/WaitAll, stored tasks, and collection-expression combinators. Help links open the documentation site, and releases publish through NuGet Trusted Publishing.