Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle entity Contains via queryable constant/parameter parameter roots #30712

Open
Tracked by #30731
roji opened this issue Apr 18, 2023 · 5 comments
Open
Tracked by #30731

Handle entity Contains via queryable constant/parameter parameter roots #30712

roji opened this issue Apr 18, 2023 · 5 comments

Comments

@roji
Copy link
Member

roji commented Apr 18, 2023

#30426 is adding support for queryable constant/parameter collections, including a Contains translation that can take advantage of e.g. OPENJSON to avoid query plan cache pollution (instead of using IN with constant expansion).

One case which was specifically excluded in #30426 is entity contains, e.g. Where(b => blogs.Contains(b)), Where(b => new Blog[] { ... }.Contains(b) (see e.g. tests List_Contains_with_constant_list, List_Contains_with_parameter_list). This was done by refraining to convert constant/parameter collections to query roots in preprocessing when their CLR type corresponds to an entity in the model. This means that this specific construct still uses IN with constant expansion.

The main difficulty with this was #30711, which makes it problematic to pattern-match the parameter case in relational.

@MikeYeager
Copy link

We're running into this problem with the following:

 var projectsWithTfs = response.Projects
         .Where(p => p.TfsServerId != null)
         .Select(p => p.TfsServerId)
         .ToList();
 var employeeTokens = context.EmployeeTfsTokens
     .Where(t => t.FkEmployee == userToken.UserId
         && projectsWithTfs.Contains(t.FkTfsServer))
     .ToList();

It seems the only way around this now is:
optionsBuilder.UseSqlServer(connectionString, o => o.UseCompatibilityLevel(120));
Is that correct?

Thank you

@roji
Copy link
Member Author

roji commented Jul 20, 2023

@MikeYeager can you please open a separate issue with a minimal, runnable repro? This is definitely something I want to look at ASAP.

@MikeYeager
Copy link

@roji Created #31323

@bachratyg
Copy link

bachratyg commented Sep 22, 2023

Would this cover passing nonprimitive collections as parameters?
e.g.

[PrimaryKey("A", "B")]
class Stuff
{
    public int A { get; set; }
    public string B { get; set; }
}
var keys = new[] { new { A=1, B="2" }, new { A=3, B="4" } };
var query = db.Stuff.Where(s => keys.Contains(new { s.A, s.B }));
// or
var query = db.Stuff.Where(s => keys.Any(k => k.A == s.A && k.B == s.B));

or is that a separate issue?

Edit: I was hoping #31369 covers this, but it seems that didn't make it into 8.0-rc1/only works on complex properties, not complex parameter collections.

@roji
Copy link
Member Author

roji commented Sep 22, 2023

@bachratyg not yet, unfortunately... EF 8.0's new complex type support does not yet include any sort of collection support - we simply did not have enough time to implement that. The plan is to hopefully complete that for 9.0 (#31237), and that would include arbitrary querying of collections of complex types as above (though the exact way this would work is still TBD).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants