0

How can I make an EF Core entity ValueGenerated property value be used when querying using Linq query with .where(), instead of the database value?

https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.valuegeneration.valuegenerator?view=efcore-8.0

For example, instead of directly translating from Linq to SQL with

(canApprove == true)

it should use:

((Approved == null && Configuration.MaxNumber > 1) == true) 

Since is the value generator logic in the class

public class Event
{
    public Configuration Configuration { get; set; }

    public bool CanApprove
    {
        get => canApprove();
        private set => _canApprove = value;
    }

    protected virtual bool canApprove() => Approved == null && Configuration.MaxNumber > 1;
}

builder.Property(e => e.CanApprove)
    .HasValueGenerator<ValueGeneratorEventCanApprove >()
    .UsePropertyAccessMode(PropertyAccessMode.Property);`

class ValueGeneratorEventCanApprove: Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator
{
    public override bool GeneratesTemporaryValues => false;

    protected override object NextValue(EntityEntry entry) => ((Event)entry.Entity).CanApprove;
}

_context.Events.Where((e) => e.CanApprove == true) should be translated to SQL as:

((Approved == null && Configuration.MaxNumber > 1) == true)

instead of

(canApprove == true)

I can't find any solution different to try unless filter by using the background fields used in the logic of .canApprove.

var query = context.Events
                   .Where(e => e.Approved == null 
                               && e.Configuration.MaxNumber > 1)
                   .Select(e => new
                                {
                                    Event = e,
                                    CanApprove = e.Approved == null && e.Configuration.MaxNumber > 1
                                })
                   .Where(e => e.CanApprove)
                   .Select(e => e.Event);

or

_context.Events.Where((e) => e.Approved == true && e.Configuration.MaxNumber> 1)

Both approaches are not good for maintenance purposes since canApprove logic is quite complex, and used in many places.

I could also make use of future events to update the canApprove values, or a batch job to do that.

3
  • Option 1, a database computed column, though since you need to join to another table that seems impossible. Option 2, just write a helper method to add the criteria IQueryable<Event> CanApprove(this IQueryable<Event> query) => query.Where(... etc...); Commented Aug 20, 2024 at 2:44
  • 1
    Or maybe a static Expression<Func<Event, bool>> CanApprove = e => e...etc...; then .Where(Event.CanApprove). Plenty of ways to reuse code and maintain it in a single place. Commented Aug 20, 2024 at 2:51
  • Very similar answer. Without third-party extensions it is not possible. Commented Aug 20, 2024 at 7:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.