yv989c / BlazarTech.QueryableValues

This library allows you to efficiently compose an IEnumerable<T> in your Entity Framework Core queries when using the SQL Server database provider.
Other
93 stars 6 forks source link

Non-intrusive Mode #13

Open yv989c opened 2 years ago

yv989c commented 2 years ago

Description

Automatically treats IEnumerable<T> types composed in a LINQ expression as if they were provided via the AsQueryableValues method. I'm assuming that the direct use of the IEnumerable<T> type is likely to have a non-constant sequence of values.

There's also the legitime case of not wanting to use QueryableValues. Like having a small list of constant values that I want hardcoded in the T-SQL, so I can use T[] or List<T> for these.

Some desired attributes:

Examples

With non-intrusive mode On, the following two queries will use QueryableValues (in both cases the values will be parameterized in the T-SQL query):

IEnumerable<int> values = Enumerable.Range(1, 10);

var myQuery1 = 
    from i in dbContext.MyEntities
    where dbContext
        .AsQueryableValues(values)
        .Contains(i.MyEntityID)
    select new
    {
        i.MyEntityID,
        i.PropA
    };

var myQuery2 = 
    from i in dbContext.MyEntities
    where values.Contains(i.MyEntityID)
    select new
    {
        i.MyEntityID,
        i.PropA
    };

With non-intrusive mode On, the first query will use QueryableValues and the second will not (the values will be hardcoded in the T-SQL instead of being parameterized):

List<int> values = Enumerable.Range(1, 10).ToList();

var myQuery1 = 
    from i in dbContext.MyEntities
    where dbContext
        .AsQueryableValues(values)
        .Contains(i.MyEntityID)
    select new
    {
        i.MyEntityID,
        i.PropA
    };

var myQuery2 = 
    from i in dbContext.MyEntities
    where values.Contains(i.MyEntityID)
    select new
    {
        i.MyEntityID,
        i.PropA
    };

Motivation

Not having to introduce an alien method (AsQueryableValues) in our EF queries is better for portability.

Ideas

Maybe be something around rewriting the original LINQ expression at some point in the EF query processing pipeline. Find IEnumerable<T> and replace with AsQueryableValues(DbContext, IEnumerable<T>).

yv989c commented 2 years ago

https://github.com/dotnet/efcore/issues/28505 should be useful (on EF 7)