aRTHUR
aRTHUR

Reputation: 1

Make entity query by ValueGenerated prop translate to computed value SQL

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.

Upvotes: 0

Views: 62

Answers (0)

Related Questions