Search code examples
c#linq.net-coreentity-framework-corenpgsql

How do I DRY query logic between IEnumerable and IQueryable?


Given two entities EntityOne and EntityTwo:

public class EntityOne
{
    public string Title { get; set; }
    public bool IsSomething { get; set; }
}
public class EntityTwo
{
    ...

    public virtual IEnumerable<EntityOne> EntityOnes { get; set; }
}

and an EntityOneFilter object like:

public class EntityOneFilter
{
    public EntityOneFilter(string? query, bool? isSomething, ...)
    {
        ...
    }
    
    public string? Query { get; }
    public bool? IsSomething { get; }
}

I'd like to reuse the query logic that can be applied to both IEnumerable<EntityOne> and IQueryable<EntityOne>:

(filter.Query == null || EF.Functions.Like(entity.Title, $"%{filter.Query}%"))
    && (!filter.IsSomething.HasValue || entity.IsSomething == filter.IsSomething.Value)
    && ...

So that it can be applied to both IQueryables coming from a DbContext:

dbContext.EntityOnes.Where(<something with filter>).FirstAsync();

and also to IEnumerable<EntityOne> that appear as a one to many collection to EntityTwo:

dbContext.EntityTwos
    .Where(e2 => e2.EntityOnes.Where(<something with filter>).Any())
    .FirstAsync();

How can I accomplish this?


Solution

  • As suggested in the comments by, I just had to use:

    dbContext.EntityTwos
        .Where(e2 => e2.EntityOnes
            .AsQueryable()
            .Where(expression).Any())
        .FirstAsync();
    

    where expression is an Expression<Func<EntityOne, bool>>.