5

I have read: Entity Framework Core - IN clause equivalent

I am trying to produce a query similar to the above post, but instead of matching a single ID, I have an array of objects. I am trying to select all matching entities from the context that match those in my list of objects.

I have an IEnumerable<PlayerRank> rankings and I am trying to select all PlayerRanks from the table that match the Date, Player, and World of those in my list.

This is the best I could come up with:

_context.PlayerRankings.Where(p => rankings.Any(k =>
                            k.Date == p.Date &&
                            k.Player == p.Player &&
                            k.World == p.World));

This ends up performing what is equivalent to a SELECT * FROM query, and pulls the entire table into memory, then filters it based on my rankings list. The table is a few million rows long, and this is pretty crippling performance wise.

An example of what the SQL might look like:

SELECT * FROM db.player_rankings
WHERE (date, player, world) IN (
    ('2017-01-18', 'Player1', 6),
    ('2017-01-18', 'Player2', 6),
    ('2017-01-18', 'Player3', 6),
    ('2017-01-18', 'Player4', 6),
    ('2017-01-18', 'Player5', 6)
)

How can I use the Fluent API to generate an WHERE IN statement to match my list of PlayerRanks?

I am using MySQL and the Pomelo connector. The Date, Player, & World are a unique index on the table.

Douglas Gaskell
  • 9,017
  • 9
  • 71
  • 128
  • How about using `rankings.Select(k => k.properties).Contains(k => p.properties)`. I don't post this as an answer as I cannot test it – Camilo Terevinto May 29 '17 at 23:04
  • You might want to look into [LinqKit](http://www.albahari.com/nutshell/linqkit.aspx), specifically the PredicateBuilder - I've found that the queries generated from that extension are (quite a bit) more sane than the default EF queries. It's built into [LinqPad](http://www.linqpad.net/), which is also useful for previewing your queries. – Tieson T. May 29 '17 at 23:09
  • @CamiloTerevinto You can't use the lambda in the contains from what I can tell. However, I did try that with working syntax and the query it executed ended up being the same as `SELECT * FROM` just with specific columns instead of `*` – Douglas Gaskell May 29 '17 at 23:16
  • How about a join? I don't know about EF Core, but in recent EF (6.1.3+ I think), you can (reasonably efficiently) join to an `IEnumerable` : `_context.PlayerRankings.Join(rankings, pr => new {pr.Date, pr.Player, pr.World}, r => new {r.Date, r.Player, r.World}, (pr, r) => pr)` . Let us know if it flies with EF Core. – spender May 29 '17 at 23:22
  • @spender Still executes the equivalent to a `SELECT * FROM` then joins in memory. – Douglas Gaskell May 29 '17 at 23:32
  • @DouglasGaskell Bummer. That's all I've got. Sorry. – spender May 29 '17 at 23:33
  • 1
    This looks like one of those areas in EF Core where the query is evaluated in-memory rather than in the database. You might want to try v 2.0 although its in Preview at the moment to see if the query translation is improved. Failing that, you might have to resort to SQL. http://www.learnentityframeworkcore.com/raw-sql – Mike Brind May 30 '17 at 15:27
  • @MikeBrind It looks like it, I tried just about everything I could find and come up with. I ended up going with rawSql. I'll self-answer with what I tried and what the final resolution seems to have been. – Douglas Gaskell May 30 '17 at 15:33
  • @DouglasGaskell could you post how you managed to work around this? I'm just starting with EF Core, and annoyingly have bumped into this issue early on, so I'm not sure if it's me using it incorrectly, or an EF Core limitation. Thanks! – Ted Sep 28 '18 at 11:06

0 Answers0