I have a specific Expression that is dynamically generated that I want to reuse in a Select statement that ultimately will be execute by EF Core as SQL in Postgres. So I am of course limited to creating expressions in a way that can be translated to SQL.
Let's call the EF Core entity in the database Thing
, it has a property Id
and I have a method GeneratePermissionsExpression
that generates an expression of the type Expression<Func<Thing, bool>>
. This is essentially a kind of permissions check, you pass it a Thing and it gives back true or false.
I'm using this expression in a different place, and now I want to reuse it here to generate a List of {Id, HasPermission}
objects, each element of the list representing this permissions check for one Thing. I can use my existing expression without issue to just generate a list of bools representing the permissions check, but in this case I also need the corresponding Ids.
What I've done so far only requires some lambda literals and the right types, but now it looks like I have to manipulate and generate Expression trees and that is a lot more complex. I tried a few things, including using Expression.Invoke, but I didn't get anywhere with that. I managed to generate an Expression representing the function "(Id, HasPermission) => new PermissionsIdResult() {Id = Id, HasPermission = HasPermission}", but failed when trying to use that to achieve my goal, and I suspect I was on entirely the wrong path there.
The code that works and only produces a list of bools looks like the following, ids
in this case is a List of ints, GeneratePermissionsExpression is the method that returns my Expression<Func<Thing, bool>>
:
var query = context.Things
.Where(t => ids.Contains(t.Id))
.Select(GeneratePermissionsExpression());
This query is then executed with ToListAsync() by EF Core.
What I now want to do looks more like the following, but obviously that code doesn't work nor compile:
var query = context.Things
.Where(t => ids.Contains(t.Id))
.Select( new ResultClass{Id = t.Id, HasPermission = GeneratePermissionsExpression());
ResultClass is simply a class containing the {Id, HasPermission}
properties, I wanted to avoid dealing with anonymous classes here. Now what the part where I write
HasPermission = GeneratePermissionsExpression()
should do is to use the Expression that method returns to fill out the HasPermission property on my ResultClass object. I tried using Invoke here, but then I get InvocationExpressions I can't run with EF Core against the database.
How can I use my Expression<Func<Thing, bool>>
to fill out the HasPermission property on that object and have all that executed in the database in the end?