Nested projection fails to translate to query
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
Research direction
Start with the repro in projection.Program.Main, reported at projection\Program.cs line 31, and inspect the RelationalProjectionBindingExpressionVisitor frames in the stack trace. Run the nested projection query and compare it with the first projection; done means the second projection translates and executes without the reported InvalidOperationException.
Written by the indexing model from the issue text.
Description
Hi.
I am trying exposing entities as projected dto-s and I have additional middleware which applies final projections to dto-s to select only specific data. Currently it fails to translate query when trying to access projected collection.
var queryable = dbContext.ClaimCases.Select(c => new ClaimDto
{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy == null
? null
: new PolicyDto
{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions.Select(tc =>
new TermsAndConditionsDto
{
Label = tc.Label,
Code = tc.Code
}).ToList()
}
});
var dto = queryable.Select(c => new ClaimDto
{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy != null
? new PolicyDto
{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions.Select(t => // if this is included it will cause exception
new TermsAndConditionsDto
{
Code = t.Code
}).ToList()
}
: null
})
.ToList();
Stack trace
Compiling query expression:
'DbSet<Claim>()
.Select(c => new ClaimDto{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy == null ? null : new PolicyDto{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions
.Select(tc => new TermsAndConditionsDto{
Label = tc.Label,
Code = tc.Code
}
)
.ToList()
}
}
)
.Select(c => new ClaimDto{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy != null ? new PolicyDto{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions
.Select(t => new TermsAndConditionsDto{ Code = t.Code }
)
.ToList()
}
: null
}
)'
Unhandled exception. System.InvalidOperationException: The LINQ expression 't' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerab
le', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMember(MemberExpression memberExpression)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitConditional(ConditionalExpression conditionalExpression)
at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at projection.Program.Main(String[] args) in C:\repos\github\ef-projection-issue\projection\Program.cs:line 31
Repro steps
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace projection
{
public static class Program
{
static void Main(string[] args)
{
using (var dbContext = new DatabaseContext())
{
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
var queryable = dbContext.ClaimCases.Select(c => new ClaimDto
{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy == null
? null
: new PolicyDto
{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions.Select(tc =>
new TermsAndConditionsDto
{
Label = tc.Label,
Code = tc.Code
}).ToList()
}
});
var dto = queryable.Select(c => new ClaimDto
{
ClaimNumber = c.ClaimNumber,
Policy = c.Policy != null
? new PolicyDto
{
PolicyNumber = c.Policy.PolicyNumber,
TermsAndConditions = c.Policy.TermsAndConditions.Select(
t => // this will cause exception
new TermsAndConditionsDto
{
Code = t.Code
}).ToList()
}
: null
})
.ToList();
}
}
}
public class Claim
{
public int Id { get; set; }
public int? PolicyId { get; set; }
public Policy Policy { get; set; }
public string ClaimNumber { get; set; }
}
public class Policy
{
public int Id { get; set; }
public string PolicyNumber { get; set; }
public List<Claim> ClaimCases { get; set; }
public List<TermsAndConditions> TermsAndConditions { get; set; }
}
public class TermsAndConditions
{
public int Id { get; set; }
public string Code { get; set; }
public string Label { get; set; }
public int PolicyId { get; set; }
public Policy Policy { get; set; }
}
public class ClaimDto
{
public string ClaimNumber { get; set; }
public PolicyDto Policy { get; set; }
}
public class PolicyDto
{
public string PolicyNumber { get; set; }
public List<TermsAndConditionsDto> TermsAndConditions = new List<TermsAndConditionsDto>();
}
public class TermsAndConditionsDto
{
public string Label { get; set; }
public string Code { get; set; }
}
public class DatabaseContext : DbContext
{
public DbSet<Claim> ClaimCases { get; set; }
public DbSet<Policy> Policies { get; set; }
public DbSet<TermsAndConditions> TermsAndConditions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=localhost;Initial Catalog=ef-projection;Integrated Security=false;User ID=sa;Password=Password1234;");
optionsBuilder.LogTo(Console.WriteLine);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Claim>().HasKey(x => x.Id);
modelBuilder.Entity<Claim>().HasIndex(p => p.ClaimNumber).IsUnique();
modelBuilder.Entity<Claim>().HasOne(x => x.Policy)
.WithMany(x => x.ClaimCases)
.HasForeignKey(x => x.PolicyId)
.HasPrincipalKey(x => x.Id)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Claim>().Property(p => p.ClaimNumber).HasMaxLength(50).IsRequired();
modelBuilder.Entity<Policy>().HasKey(p => p.Id);
modelBuilder.Entity<Policy>().Property(p => p.PolicyNumber).HasMaxLength(50).IsRequired();
modelBuilder.Entity<TermsAndConditions>().HasKey(p => p.Id);
modelBuilder.Entity<TermsAndConditions>().Property(x => x.Code).HasMaxLength(50).IsRequired();
modelBuilder.Entity<TermsAndConditions>().Property(x => x.Label).HasMaxLength(50).IsRequired();
modelBuilder.Entity<TermsAndConditions>().HasOne(x => x.Policy)
.WithMany(policy => policy.TermsAndConditions)
.HasForeignKey(x => x.PolicyId);
base.OnModelCreating(modelBuilder);
}
}
}
Provider and version information
EF Core version: 5.0.11
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.1
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 134
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/efcore
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
customer-reported
Difficulty 5/5 Over a week Newbie friendliness 38/100
-
area-cosmos area-vector-search
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-cosmos
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-tools needs-design
Difficulty 4/5 3-5 days Newbie friendliness 25/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100