question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Condition and Ordering when projecting inheritance tree of entities don't work

See original GitHub issue

Hi, i know the subject as been discussed a lot and it’s complex but i wanted to share my interest to this issue. I’m trying to project a set of entities with some inheritance. I’ve made a sample project to show my issue.

AutoMapperInheritance.zip

Steps to reproduce

Entities : I’ve got 3 Db Entities (each mapped to their class, the issue is the same with any inheritance db model) MainEntity (the base abstract class) SubEntity1 : MainEntity SubEntity2 : MainEntity

Dtos: I’ve got 3 dtos model MainDto (also abstract) SubDto1 : MainDto SubDto2 : MainDto

A “by hand” automapper conversion method that transform Entities to Model (and vise versa), because i would like to use automapper to do the conversion but wanted to be sure it’s an ef core issue.

Now the issue : if i try to create a query of all MainEntities (SubEntity1 + SubEntity2) the request crash when i add a WHERE condition or an ORDERBY condition.

IQueryable<MainDto> query = context.Entities.ToModel();
                   
//Those call are working !
IEnumerable<MainDto> entites = query.ToList();
IEnumerable<MainDto> entitesSkipTake = query.Skip(5).Take(5).ToList();
//Those ones don't
IEnumerable<MainDto> entitesOrderBy = query.OrderBy(p => p.Id).ToList();
IEnumerable<MainDto> entitesWhere = query.Where(p => p.Property0.Contains("Test")).ToList();

The thing that seems strange is that the “simple” select and projection are working and give this sql requests :

SELECT [e].[Id], [e].[Property0], [s].[Property1], [s0].[Property2], CASE
          WHEN [s].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity1], CASE
          WHEN [s0].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity2]
      FROM [ENTITIY] AS [e]
      LEFT JOIN [SUBENTITY1] AS [s] ON [e].[Id] = [s].[Id]
      LEFT JOIN [SUBENTITY2] AS [s0] ON [e].[Id] = [s0].[Id]

then the skip and take one :

SELECT [e].[Id], [e].[Property0], [s].[Property1], [s0].[Property2], CASE
          WHEN [s].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity1], CASE
          WHEN [s0].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity2]
      FROM [ENTITIY] AS [e]
      LEFT JOIN [SUBENTITY1] AS [s] ON [e].[Id] = [s].[Id]
      LEFT JOIN [SUBENTITY2] AS [s0] ON [e].[Id] = [s0].[Id]
      ORDER BY (SELECT 1)
      OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY

but when it comes for the order by and the where it’s crashing with the known :

.OrderBy(m => m
        .ToModel().Id)' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

the thing is it would seems that the query could easily be made in sql (at a first see of course) the order by one could be :

SELECT [e].[Id], [e].[Property0], [s].[Property1], [s0].[Property2], CASE
          WHEN [s].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity1], CASE
          WHEN [s0].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity2]
      FROM [ENTITIY] AS [e]
      LEFT JOIN [SUBENTITY1] AS [s] ON [e].[Id] = [s].[Id]
      LEFT JOIN [SUBENTITY2] AS [s0] ON [e].[Id] = [s0].[Id]
      ORDER BY [e].[Id]

and the WHERE one

SELECT [e].[Id], [e].[Property0], [s].[Property1], [s0].[Property2], CASE
          WHEN [s].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity1], CASE
          WHEN [s0].[Id] IS NOT NULL THEN CAST(1 AS bit)
          ELSE CAST(0 AS bit)
      END AS [IsSubEntity2]
      FROM [ENTITIY] AS [e]
      LEFT JOIN [SUBENTITY1] AS [s] ON [e].[Id] = [s].[Id]
      LEFT JOIN [SUBENTITY2] AS [s0] ON [e].[Id] = [s0].[Id]
      WHERE [e].[Id] IS NOT NULL AND ([e].[Property0] LIKE N'%Test%')

So now the question what am i not understanding that make ef core not able to handle this kind of request… (yes because it could be so cool that it could !!!)

Thanks for all your work and your amazing tools !

Further technical details

EF Core version: 3.1.0 and 5.0.0-preview.8.20407.4 Database provider: Microsoft.EntityFrameworkCore.SqlServer@5.0.0-preview.8.20407.4 Target framework: .NET Core 3.1 Operating system: IDE: Visual Studio 2019 16.4

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
smitpatelcommented, Sep 9, 2020

They are not same query as the one in the repro code. Specifically ToModel method call is not inside any lambda passed to another method. When you use ToModel outside of lambda then it will actually be inlined in the tree. When you use that inside a lambda function, compiler injects ToModel method in the tree. We cannot look into ToModel method if it is integrated in the tree.

0reactions
ajcvickerscommented, Sep 14, 2020

Note from triage: putting on the backlog to consider supporting this kind translation in the future.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Projection with inheritance tree based on abstract class
Hi, i'm trying to project an IQueryable datasource composed of multiple different types based on the same abstract class.
Read more >
Entity Framework OrderBy on field from projection
I want to sort on a field only known at runtime, and that field may be constructed inside the select clause. Requirements: User...
Read more >
What's New in EF Core 7.0
Determines what order to insert, update, and delete entities so that database constraints are not violated; Ensures database generated values ...
Read more >
New type of CDS entity available: CDS projection views
This blog post explains what a CDS projection view is, what it does, ... and element annotations) are inherited from the projected entity...
Read more >
Resolving a logical entity definition - Common Data Model
While projection operations can be conditionally executed, it's important to recognize that any projections included in an entity definition ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found