dotnet/efcore · error · InvalidOperationException
Cannot translate the '{comparisonOperator}' on an expression
Error message
Cannot translate the '{comparisonOperator}' on an expression of entity type '{entityType}' because it is a keyless entity. Consider using entity properties instead. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943. What it means
Thrown from TryRewriteContainsEntity when an item passed to Queryable.Contains references an entity type that has no primary key (keyless). Without a key the translator cannot reduce entity equality to a key comparison, so it rejects the Contains.
Source
Thrown at src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs:1268
return expression is MethodCallExpression { Method.IsGenericMethod: true } readValueMethodCall
&& readValueMethodCall.Method.GetGenericMethodDefinition() == ExpressionExtensions.ValueBufferTryReadValueMethod
? readValueMethodCall.Arguments[2].GetConstantValue<IProperty>()
: null;
}
private bool TryRewriteContainsEntity(Expression? source, Expression item, [NotNullWhen(true)] out Expression? result)
{
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 =View on GitHub (pinned to 3a2006ef56)
Solutions
- Configure a primary key on the entity (HasKey(...) or by convention) if the underlying rows are uniquely identifiable.
- Rewrite the Contains to compare a primitive key property instead of the whole entity: db.Items.Select(i => i.Id).Contains(id).
- If the type is genuinely keyless, perform the membership check client-side via AsEnumerable().
- Re-evaluate whether the type should be keyless — most entities need a key.
Example fix
// before db.Views.Contains(viewEntity); // after - compare by a property db.Views.Select(v => v.Code).Contains(viewEntity.Code);
Defensive patterns
Strategy: validation
Validate before calling
var et = dbContext.Model.FindEntityType(typeof(MyView));
if (et?.FindPrimaryKey() is null)
throw new InvalidOperationException("Cannot use Contains on keyless MyView; compare a property"); Type guard
static bool IsKeyless(IEntityType et) => et.FindPrimaryKey() is null;
Try / catch
try { return db.Views.Contains(item); }
catch (InvalidOperationException ex) when (ex.Message.Contains("keyless entity"))
{
return db.Views.AsEnumerable().Contains(item);
} Prevention
- Define a primary key on every entity that participates in Contains/equality.
- Compare a single primitive key property instead of the whole entity.
- Reserve HasNoKey for genuinely keyless query results.
When it happens
Trigger: A query like db.MyView.Contains(entity) where MyView is configured HasNoKey() and the item is a StructuralTypeReferenceExpression whose StructuralType is a keyless IEntityType.
Common situations: Using Contains/ equality against a keyless entity (a view, a raw SQL result, or a query result without keys). Forgetting to define a primary key on an entity mapped to a database view.
Related errors
- Cannot translate '{comparisonOperator}' on a subquery expres
- The LINQ expression '{expression}' could not be translated.
- Translation of '{expression}' failed. Either the query sourc
- Cannot translate the '{comparisonOperator}' on an expression
- Cannot translate '{comparisonOperator}' on a subquery expres
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/ece3dc7c555d4042.
Report an issue: GitHub.