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 by TryRewriteContainsEntity when a Contains operates on a subquery whose entity type has a composite primary key (more than one key property). The Cosmos provider's Contains rewrite extracts a single key property into a list; with a composite key it cannot produce a valid single-value Contains, so it throws.
Source
Thrown at src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.StructuralEquality.cs:42
{
result = null;
if (item is not StructuralTypeReferenceExpression { StructuralType: IEntityType entityType })
{
return false;
}
var primaryKeyProperties = entityType.FindPrimaryKey()?.Properties;
switch (primaryKeyProperties)
{
case null:
throw new InvalidOperationException(
CoreStrings.EntityEqualityOnKeylessEntityNotSupported(
nameof(Queryable.Contains), entityType.DisplayName()));
case { Count: > 1 }:
throw new InvalidOperationException(
CoreStrings.EntityEqualityOnCompositeKeyEntitySubqueryNotSupported(
nameof(Queryable.Contains), entityType.DisplayName()));
}
var property = primaryKeyProperties[0];
Expression rewrittenSource;
switch (source)
{
case SqlConstantExpression sqlConstantExpression:
var values = (IEnumerable)sqlConstantExpression.Value!;
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 dbf9771522)
Solutions
- Rewrite the Contains as an Any with a predicate comparing all composite key properties: subquery.Any(x => x.K1 == e.K1 && x.K2 == e.K2).
- Project a single discriminant value (e.g. a concatenated id) from the subquery and Contains on that.
- Materialize the subquery results client-side and compare composite keys in memory.
Example fix
// before
var exists = await context.Items.Where(...).Contains(item).AnyAsync();
// after
var exists = await context.Items.Where(...)
.AnyAsync(x => x.K1 == item.K1 && x.K2 == item.K2); Defensive patterns
Strategy: validation
Validate before calling
// For composite keys, use Any with a multi-property predicate var exists = await subquery.AnyAsync(x => x.K1 == item.K1 && x.K2 == item.K2);
Prevention
- Avoid Contains over subqueries returning composite-key entities.
- Rewrite as Any comparing all composite key properties.
- Project a single discriminant value when Contains semantics are required.
When it happens
Trigger: Calling Contains on the result of a subquery returning entities with composite keys, e.g. subquery.Where(...).Contains(entity) where the entity has multiple PK properties.
Common situations: Entities modeled with composite keys used in Contains against a subquery. Relational patterns ported to Cosmos where composite-key Contains was supported differently.
Related errors
- Cannot translate the '{comparisonOperator}' on an expression
- The '{methodName}' method is not supported because the query
- The LINQ expression '{expression}' could not be translated.
- A FromSqlExpression has an invalid arguments expression type
- The LINQ expression '{expression}' could not be translated.
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/f7ba9f9ec4274544.
Report an issue: GitHub.