Rule reference
LinqContraband Rule Catalog
Full LinqContraband EF Core analyzer rule catalog grouped by query, materialization, loading, async, tracking, raw SQL, and schema design.
The source of truth for rule metadata lives in src/LinqContraband/Catalog/RuleCatalog.cs. This page is generated from that catalog and grouped by EF Core failure mode.
8 diagnostic domains
Bulk Operations & Set-Based Writes
Keep destructive and high-volume writes set-based while making the risky cases explicit.
Optimize: Use ExecuteDelete() instead of RemoveRange()
Suggests ExecuteDelete() instead of RemoveRange() for EF Core bulk deletes, removing rows in one SQL DELETE without loading them first.
Samples/LC012_OptimizeRemoveRange/ LC032 InfoUse ExecuteUpdate for provable bulk scalar updates
Detects loops that load EF Core entities only to set scalar properties and save, and suggests one set-based ExecuteUpdate() call instead.
Samples/LC032_ExecuteUpdateForBulkUpdates/ LC035 InfoMissing Where before bulk execute
Flags EF Core ExecuteDelete and ExecuteUpdate calls with no proven Where filter, which delete or rewrite every row in the table.
Samples/LC035_MissingWhereBeforeExecuteDeleteUpdate/ LC047 WarningExecuteDelete bypasses the tracked delete pipeline
Flags ExecuteDelete when SaveChanges logic such as soft delete or client cascades must run, since SQL DELETE skips that tracked pipeline.
Samples/LC047_ExecuteDeleteBypassesTrackedDelete/Change Tracking & Context Lifetime
Spot DbContext lifetime leaks, tracking-mode surprises, and writes that silently do nothing.
Performance: Missing AsNoTracking() in Read-Only path
Suggests AsNoTracking() for read-only EF Core queries, so the change tracker does not snapshot entities the code never modifies.
Samples/LC009_MissingAsNoTracking/ LC010 WarningN+1 Write Problem: SaveChanges inside loop
Flags SaveChanges or SaveChangesAsync inside a loop, which costs one database round trip per item instead of one batched save.
Samples/LC010_SaveChangesInLoop/ LC013 WarningDisposed Context Query
Detects an IQueryable or IAsyncEnumerable returned after its DbContext is disposed, which throws when the caller finally enumerates it.
Samples/LC013_DisposedContextQuery/ LC025 WarningAvoid AsNoTracking with Update/Remove
Detects entities loaded with AsNoTracking() and then passed to Update or Remove, which can overwrite every column or fail on identity conflicts.
Samples/LC025_AsNoTrackingWithUpdate/ LC030 InfoPotential DbContext lifetime mismatch
Flags singletons and hosted services that store a DbContext, a lifetime mismatch that leads to threading errors and stale data. Use a factory.
Samples/LC030_DbContextInSingleton/ LC039 InfoAvoid repeated SaveChanges on the same context
Flags repeated SaveChanges calls on the same DbContext in one method, which add round trips and can leave partial writes. Save once.
Samples/LC039_NestedSaveChanges/ LC040 InfoAvoid mixing tracking modes on the same context
Flags methods that mix tracked and AsNoTracking() queries on the same DbContext, which makes later update behavior hard to predict.
Samples/LC040_MixedTrackingAndNoTracking/ LC044 WarningAsNoTracking query mutated then SaveChanges — silent data loss
Detects entities loaded with AsNoTracking(), modified, then followed by SaveChanges, which silently saves nothing: data loss with no error.
Samples/LC044_AsNoTrackingThenModify/ LC048 WarningTracked update can overwrite a concurrent change
Detects tracked EF Core read-modify-write updates, such as counters, saved without a concurrency token, so concurrent requests overwrite each other.
Samples/LC048_LostUpdateRisk/ LC059 WarningConnection owned by the DbContext is disposed
Flags code that disposes the connection from EF Core GetDbConnection(), which the DbContext owns, breaking later queries and SaveChanges.
Samples/LC059_DisposedContextConnection/Execution & Async
Find synchronous calls, repeated database execution, and async paths that drop cancellation or buffer too early.
N+1 Problem: Database execution inside loop
Finds EF Core N+1 queries: Find, ToList, Count and other database calls that provably run once per loop iteration instead of once.
Samples/LC007_NPlusOneLooper/ LC008 WarningSync-over-Async: Synchronous EF Core method in Async context
Flags synchronous EF Core calls such as ToList or SaveChanges inside async methods, where they block threads. Use the Async counterpart.
Samples/LC008_SyncBlocker/ LC026 InfoMissing CancellationToken in async call
Flags EF Core async calls that omit an available CancellationToken, so cancelled requests keep running queries against the database.
Samples/LC026_MissingCancellationToken/ LC036 WarningDbContext captured by thread work item
Detects one DbContext captured by Task.Run, Parallel.ForEach, threads or timers. DbContext is not thread-safe, so use one context per task.
Samples/LC036_DbContextCapturedAcrossThreads/ LC043 InfoPrefer await foreach over buffering async streams
Flags an IAsyncEnumerable buffered with ToListAsync or ToArrayAsync only to loop over it once. Use await foreach to stream instead.
Samples/LC043_AsyncEnumerableBuffering/ LC046 WarningConcurrent EF Core operations on the same DbContext
Detects overlapping async operations on the same DbContext instance, which EF Core rejects at runtime. Await each call or use separate contexts.
Samples/LC046_ConcurrentDbContextOperations/ LC051 WarningToAsyncEnumerable() runs an EF Core query synchronously
Flags ToAsyncEnumerable() on EF Core queries, which enumerates them synchronously and blocks a thread per row, and switches to AsAsyncEnumerable().
Samples/LC051_ToAsyncEnumerableOnQuery/ LC058 WarningTransactionScope without async flow spans an await
Flags a TransactionScope created without TransactionScopeAsyncFlowOption.Enabled in async code, where the transaction is lost after an await.
Samples/LC058_TransactionScopeWithoutAsyncFlow/ LC060 WarningEF Core async operator on an in-memory query
Flags EF Core ToListAsync, CountAsync and other async operators on AsQueryable() over an in-memory collection, which throw at run time.
Samples/LC060_AsyncOnInMemoryQuery/ LC062 WarningBlocking on an EF Core async call
Flags .Result, .Wait() and .GetAwaiter().GetResult() on EF Core async calls, which starve the thread pool and deadlock under a SynchronizationContext.
Samples/LC062_BlockingEfAsyncCall/ LC063 WarningUser transaction under a retrying execution strategy
Flags BeginTransaction on an EF Core context set up with EnableRetryOnFailure, which throws unless the transaction runs in the execution strategy.
Samples/LC063_TransactionUnderRetryingStrategy/Loading & Includes
Make relationship loading deliberate before N+1 round trips or over-eager include graphs reach production.
Cartesian Explosion Risk: Multiple Collection Includes
Detects sibling collection Include paths without AsSplitQuery(), where EF Core joins them into a Cartesian product that multiplies the rows returned.
Samples/LC006_CartesianExplosion/ LC019 WarningConditional Include Expression
Flags ternary and null-coalescing expressions inside EF Core Include paths, which cannot translate. Apply the Include conditionally instead.
Samples/LC019_ConditionalInclude/ LC028 WarningDeep ThenInclude Chain
Flags EF Core ThenInclude chains deeper than the configured limit, which load large object graphs. Project or split the query instead.
Samples/LC028_DeepThenInclude/ LC038 InfoAvoid excessive eager loading
Flags EF Core queries with more Include and ThenInclude steps than the configured threshold, which load oversized graphs in one query.
Samples/LC038_ExcessiveEagerLoading/ LC042 InfoComplex query should be tagged
Flags complex EF Core queries without TagWith() or TagWithCallSite(), so the SQL they produce is hard to trace back to code in logs.
Samples/LC042_MissingQueryTags/ LC045 WarningMissing Include: navigation accessed on materialized entity
Detects navigation properties read after an EF Core query without a matching Include, causing N+1 lazy loads or null and empty data.
Samples/LC045_MissingInclude/ LC049 InfoInclude is ignored by a Select projection
Flags EF Core Include calls that a later Select projection makes EF Core ignore, and removes them.
Samples/LC049_IncludeIgnoredByProjection/Materialization & Projection
Keep work in SQL where it belongs and avoid loading whole entities or unbounded result sets by accident.
Premature query continuation after materialization
Catches ToList, ToArray or AsEnumerable before Where, Select or OrderBy, which moves EF Core query work out of SQL and into memory.
Samples/LC002_PrematureMaterialization/ LC003 WarningPrefer Any() over Count() existence checks
Flags Count() > 0 style existence checks on EF Core queries and suggests Any() or AnyAsync(), which can stop at the first matching row.
Samples/LC003_AnyOverCount/ LC017 InfoPerformance: Consider using Select() projection
Flags EF Core queries that load whole entities when only a few properties are used. Project with Select to fetch just the needed columns.
Samples/LC017_WholeEntityProjection/ LC022 InfoNested collection materialization inside projection
Flags ToDictionary on a nested collection in an EF Core Select projection, which throws, and nested ToList on EF Core 7 or older.
Samples/LC022_ToListInSelectProjection/ LC023 InfoUse Find/FindAsync for primary key lookups
Suggests Find or FindAsync when FirstOrDefault or SingleOrDefault looks up an EF Core entity by primary key, so tracked entities skip the database.
Samples/LC023_FindInsteadOfFirstOrDefault/ LC029 InfoRedundant identity Select
Flags Select(x => x) in LINQ and EF Core query chains. The identity projection does nothing and only adds noise to the expression tree.
Samples/LC029_RedundantIdentitySelect/ LC031 InfoUnbounded Query Materialization
Flags EF Core queries materialized with no filter or Take limit, which can load an entire table into memory as the data grows.
Samples/LC031_UnboundedQueryMaterialization/ LC033 InfoUse FrozenSet for provably read-only membership caches
Flags private static readonly HashSet lookup caches that are never mutated and suggests FrozenSet on .NET 8+ for faster membership checks.
Samples/LC033_UseFrozenSetForStaticMembershipCaches/ LC041 InfoSingle entity query over-fetches one consumed property
Flags First or Single queries that load a whole EF Core entity when only one property is read. Select that property to fetch one column.
Samples/LC041_SingleEntityScalarProjection/ LC057 WarningMin, Max or Average throws on an empty query
Flags EF Core Min, Max and Average over a non-nullable value, which throw 'Sequence contains no elements' when no row matches.
Samples/LC057_EmptyQueryAggregate/Query Shape & Translation
Catch LINQ patterns that EF Core cannot translate reliably or cannot page deterministically.
Client-side evaluation risk: Local method usage in IQueryable
Flags your own helper methods inside EF Core IQueryable lambdas that SQL cannot translate, which forces client-side evaluation or a runtime error.
Samples/LC001_LocalMethod/ LC004 WarningDeferred Execution Leak: IQueryable passed as IEnumerable
Detects an EF Core IQueryable passed as IEnumerable to a method that enumerates it, so filtering runs in memory instead of in SQL.
Samples/LC004_IQueryableLeak/ LC005 WarningMultiple OrderBy calls
Flags a second OrderBy or OrderByDescending in one LINQ chain, which silently discards the first sort. Use ThenBy or ThenByDescending.
Samples/LC005_MultipleOrderBy/ LC014 WarningAvoid String.ToLower() or ToUpper() in LINQ queries
Flags ToLower() and ToUpper() on entity properties in EF Core queries, which can stop the database using an index. Use a collation instead.
Samples/LC014_AvoidStringCaseConversion/ LC015 WarningDeterministic Pagination: OrderBy required before Skip/Take
Flags Skip, Take, Last, ElementAt and Chunk on unordered EF Core queries, where the database may return rows in a different order each run.
Samples/LC015_MissingOrderBy/ LC016 WarningAvoid DateTime.Now/UtcNow in LINQ queries
Flags DateTime.Now, UtcNow and DateTimeOffset.Now inside EF Core LINQ queries. Hoist the value into a local for cacheable, testable queries.
Samples/LC016_AvoidDateTimeNow/ LC020 WarningAvoid untranslatable string comparison overloads
Flags Contains, StartsWith and EndsWith with a StringComparison argument in EF Core queries, which providers often cannot translate to SQL.
Samples/LC020_StringContainsWithComparison/ LC024 WarningGroupBy with Non-Translatable Projection
Flags EF Core GroupBy queries that project values SQL cannot translate, which causes runtime errors or accidental client-side grouping.
Samples/LC024_GroupByNonTranslatable/ LC050 WarningOrderBy before Distinct is discarded
Flags EF Core queries that sort before Distinct(), where SQL DISTINCT silently drops the ORDER BY, and moves the sort after Distinct().
Samples/LC050_OrderByBeforeDistinct/ LC061 WarningCompiled query is not cached
Flags EF Core EF.CompileQuery and EF.CompileAsyncQuery calls that compile the query on every call instead of once in a static readonly field.
Samples/LC061_UncachedCompiledQuery/Raw SQL & Security
Flag SQL construction patterns that can bypass parameterization, tenant filters, or review expectations.
Avoid FromSqlRaw with interpolated strings
Flags FromSqlRaw and SqlQueryRaw called with interpolated or concatenated SQL, an injection risk. Use FromSql or SQL parameters instead.
Samples/LC018_AvoidFromSqlRawWithInterpolation/ LC021 WarningAvoid IgnoreQueryFilters
Flags IgnoreQueryFilters() in EF Core queries, which bypasses global filters for soft delete, multi-tenancy or security and can leak data.
Samples/LC021_AvoidIgnoreQueryFilters/ LC034 WarningAvoid ExecuteSqlRaw with interpolated strings
Flags ExecuteSqlRaw and ExecuteSqlRawAsync called with interpolated or concatenated SQL, an injection risk. Use ExecuteSql or parameters.
Samples/LC034_AvoidExecuteSqlRawWithInterpolation/ LC037 WarningAvoid constructed raw SQL strings
Flags SQL built with concatenation, string.Format or StringBuilder before it reaches FromSqlRaw, ExecuteSqlRaw or SqlQueryRaw: an injection risk.
Samples/LC037_RawSqlStringConstruction/ LC056 WarningLINQ composed over a stored procedure call
Flags EF Core FromSql, FromSqlRaw and SqlQuery calls that run a stored procedure (EXEC) and are then composed with LINQ, which throws at run time.
Samples/LC056_StoredProcedureComposed/Schema & Modeling
Guard model shape choices that produce fragile entity mappings and unclear relationships.
Design: Entity missing Primary Key
Detects EF Core entity types exposed through a DbSet that have no primary key from convention, a [Key] attribute or fluent configuration.
Samples/LC011_EntityMissingPrimaryKey/ LC027 InfoMissing Explicit Foreign Key Property
Flags EF Core reference navigations whose dependent entity has no matching foreign key property, leaving EF Core to create a shadow key.
Samples/LC027_MissingExplicitForeignKey/ LC052 WarningModel data uses a value that changes on every run
Flags HasData and HasDefaultValue with DateTime.Now or Guid.NewGuid(), which change the EF Core model every run and make EF Core 9 Migrate() throw.
Samples/LC052_NonDeterministicModelData/ LC053 WarningGlobal query filter silently replaced by another HasQueryFilter
Flags a second unnamed EF Core HasQueryFilter on one entity, which replaces the first and silently drops a tenant or soft-delete filter.
Samples/LC053_OverwrittenQueryFilter/ LC054 WarningMigrate called inside a user transaction
Flags EF Core Database.Migrate() and MigrateAsync() calls inside a transaction begun on the same context, which EF Core 9 and later reject at startup.
Samples/LC054_MigrateInsideTransaction/ LC055 WarningOnModelCreating override skips the base configuration
Flags EF Core OnModelCreating overrides that never call base.OnModelCreating when the base context, such as IdentityDbContext, configures the model.
Samples/LC055_MissingBaseOnModelCreating/