dotnet / dotnet/efcore

EF.Property fails after conditional projection of entity into anonymous type

Open
#35,733 3 comments 0 reactions 0 assignees View on GitHub
area-query customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

### Bug description

I have a routine that receive an expression that contains a query and it have to apply a projection

Having this semplified DBContext and Model :

```
public class TestContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer("Data Source=DESKTOP-6Q8KE4E\\MSSQLSERVER2022;Integrated Security=SSPI;Initial Catalog=ApplyProjection;Encrypt=False");
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity().HasKey(itm => itm.ID);
modelBuilder.Entity().HasKey(itm => itm.ID);
modelBuilder.Entity().HasOne(itm=>itm.Master).WithMany(itm=>itm.Details);

}
}

public class Master
{
public Guid ID { get; set; }
public string Description { get; set; }

public virtual ICollection Details { get; set; }
}

public class Detail
{
public Guid ID { get; set; }
public string Description { get; set; }

public virtual Master Master { get; set; }
}

```

If, for example, I receive this query

```
var q1 = dbContext.Set().Select(itm => itm.Description.Contains("1") ?
new { itm, PropertyA = 1 } :
new { itm, PropertyA = 2 })

```
I can apply this projection :
```
.Select(itm => itm.PropertyA == 1 ?
new { P0 = itm.itm.ID, P1 = "X" } :
new { P0 = itm.itm.ID, P1 = "Y" });

```
so the full query became
```
var q1 = dbContext.Set().Select(itm => itm.Description.Contains("1") ?
new { itm, PropertyA = 1 } :
new { itm, PropertyA = 2 })
.Select(itm => itm.PropertyA == 1 ?
new { P0 = itm.itm.ID, P1 = "X" } :
new { P0 = itm.itm.ID, P1 = "Y" }).ToArray()

```
and this query works.

But if I try to access to a shadow property of the entity :
```
.Select(itm => itm.PropertyA == 1 ?
new { P0 = EF.Property(itm, "MasterID"), P1 = "X" } :
new { P0 = EF.Property(itm, "MasterID"), P1 = "Y" })

```
with this full query :
```
var q2 = dbContext.Set().Select(itm => itm.Description.Contains("1") ?
new { itm, PropertyA = 1 } :
new { itm, PropertyA = 2 })
.Select(itm => itm.PropertyA == 1 ?
new { P0 = EF.Property(itm, "MasterID"), P1 = "X" } :
new { P0 = EF.Property(itm, "MasterID"), P1 = "Y" }).ToArray();

```
this not works with :
```
System.InvalidOperationException
HResult=0x80131509
Message=Translation of 'EF.Property(StructuralTypeShaperExpression(
StructuralType: ConsoleApp1.Detail
ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False).Description.Contains("1") ? new {
itm = StructuralTypeShaperExpression(
StructuralType: ConsoleApp1.Detail
ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False),
PropertyA = 1
} : new {
itm = StructuralTypeShaperExpression(
StructuralType: ConsoleApp1.Detail
ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False),
PropertyA = 2
}, "MasterID")' failed. Either the query source is not an entity type, or the specified property does not exist on the entity type.
Origine=Microsoft.EntityFrameworkCore.Relational
Analisi dello stack:
in Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
in Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
in Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
in Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateProjection(Expression expression, Boolean applyDefaultTypeMapping)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitNew(NewExpression newExpression)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitConditional(ConditionalExpression conditionalExpression)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
in Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
in Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
in Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
in Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
in Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
in Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression query)
in Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
in Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
in Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
in Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass11_0`1.b__0()
in Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
in Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
in Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
in Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
in Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
in System.Collections.Generic.SegmentedArrayBuilder`1.AddNonICollectionRangeInlined(IEnumerable`1 source)
in System.Linq.Enumerable.g__EnumerableToArray|314_0[TSource](IEnumerable`1 source)
in ConsoleApp1.Program.Main(String[] args) in D:\VM\G\ConsoleApp1\ConsoleApp1\Program.cs: riga 29

```
So, I can access to a model property of the entity but not to a shadow property. Actually the message "Either the query source is not an entity type" seem say that if the source is an entity type I can access to its properties .

So, is it possible to add the option to access also to shadows properties?

### Your code

```csharp
https://github.com/GLuca74/ApplyProjectionAndShadowProperty
```

### Stack traces

```text

```

### Verbose output

```text

```

### EF Core version

9.0.0

### Database provider

_No response_

### Target framework

9.0.0_

### Operating system

Windows 10

### IDE

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.