dotnet/efcore · error · InvalidOperationException
Cannot translate '{comparisonOperator}' on a subquery expres
Error message
Cannot translate '{comparisonOperator}' on a subquery expression of entity type '{entityType}' because it has a composite primary key. See https://go.microsoft.com/fwlink/?linkid=2141942 for information on how to rewrite your query. What it means
Thrown from TryRewriteContainsEntity when Contains is applied to a subquery whose entity type has a composite primary key (more than one key property). The InMemory translator can only rewrite Contains over single-key entities; composite-key entity subqueries have no single column to expand into an IN list.
Source
Thrown at src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs:1275
{
result = null;
if (item is not StructuralTypeReferenceExpression { StructuralType: IEntityType entityType })
{
return false;
}
var primaryKeyProperties = entityType.FindPrimaryKey()?.Properties;
if (primaryKeyProperties == null)
{
throw new InvalidOperationException(
CoreStrings.EntityEqualityOnKeylessEntityNotSupported(
nameof(Queryable.Contains), entityType.DisplayName()));
}
if (primaryKeyProperties.Count > 1)
{
throw new InvalidOperationException(
CoreStrings.EntityEqualityOnCompositeKeyEntitySubqueryNotSupported(
nameof(Queryable.Contains), entityType.DisplayName()));
}
var property = primaryKeyProperties[0];
Expression rewrittenSource;
switch (source)
{
case ConstantExpression constantExpression:
var values = constantExpression.GetConstantValue<IEnumerable>();
var propertyValueList =
(IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(property.ClrType.MakeNullable()))!;
var propertyGetter = property.GetGetter();
foreach (var value in values)
{
propertyValueList.Add(propertyGetter.GetClrValue(value));
}
View on GitHub (pinned to 3a2006ef56)
Solutions
- Rewrite Contains on a composite-key entity as a JOIN on all key columns, or as multiple paired Where conditions.
- Materialize the subquery with AsEnumerable() and perform the Contains client-side.
- Project to a tuple/string key and Contains on that single value: db.Orders.Select(o => new { o.A, o.B }).AsEnumerable().Contains(...).
- Avoid Contains over composite-key subqueries; prefer Any(x => x.A == a && x.B == b).
Example fix
// before db.Joins.Contains(joinEntity); // after db.Joins.Any(j => j.A == joinEntity.A && j.B == joinEntity.B);
Defensive patterns
Strategy: validation
Validate before calling
var pk = dbContext.Model.FindEntityType(typeof(Join))?.FindPrimaryKey();
if (pk is { Properties.Count: > 1 })
throw new InvalidOperationException("Composite-key entity: use Any(...) instead of Contains over a subquery"); Type guard
static bool HasCompositeKey(IEntityType et)
=> et.FindPrimaryKey()?.Properties.Count > 1; Try / catch
try { return db.Joins.Contains(item); }
catch (InvalidOperationException ex) when (ex.Message.Contains("composite primary key"))
{
return db.Joins.Any(j => j.A == item.A && j.B == item.B);
} Prevention
- Avoid Contains over composite-key entity subqueries; use Any on all key columns.
- Project to a single string/tuple key for membership checks.
- Materialize with AsEnumerable() if Contains is unavoidable.
When it happens
Trigger: Queryable.Contains over a subquery (e.g. db.Orders.Contains(order) where db.Orders is itself a subquery, or the source is a ConstantExpression of entities) and the entity's FindPrimaryKey().Properties.Count > 1.
Common situations: Entities with composite keys (junction tables, many-to-many join entities) used inside a Contains against a subquery. Refactoring equality checks to use Contains when moving to composite keys.
Related errors
- Cannot translate the '{comparisonOperator}' on an expression
- The LINQ expression '{expression}' could not be translated.
- Translation of '{expression}' failed. Either the query sourc
- Cannot translate '{comparisonOperator}' on a subquery expres
- Cannot translate the '{comparisonOperator}' on an expression
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/3662e9fddd4881a1.
Report an issue: GitHub.