Linq-to-Entities match ID in list of integers in a compiled query
-
14-11-2019 - |
Question
I'm trying to find a way to implement a Linq-to-Entities compiled query of the form:
Func<MyEntities, List<int>, IQueryable<MyClass>> query = System.Data.Objects.CompiledQuery.Compile(
(MyEntities entities, List<int> IDs) => (
(from au in entities.Mine where IDs.Any(x => x == au.ID) select au)
));
Because only scalar parameters can be passed to CompiledQuery.Compile the above fails. I'm trying to find some clever way to pass a comma delimited list of integers as a string and use that in the L2E query along the lines of:
Func<MyEntities, string, IQueryable<MyClass>> query = System.Data.Objects.CompiledQuery.Compile(
(MyEntities entities, string IDs) => (
(from au in entities.Mine where IDs.Split(',').Any(x => Convert.ToInt32(x) == au.ID) select au)
));
But that doesn't work due to the unsupported Split function.
Any clever ideas about how this could be implemented?
Solution 2
I ended up finding a way to do it but it's way too slow at around 3s.
string ids = "|" + String.Join("|", new List<int> { 4, 5, 6, 7, 8, 9, 10, 20, 23, 34 }) + "|";
Func<MyEntities, string, IQueryable<MyClass>> query = System.Data.Objects.CompiledQuery.Compile(
(MyEntities entities, string IDs) => (
(from au in entities.Mine where IDs.Contains("|" + SqlFunctions.StringConvert((decimal)au.ID).Trim() + "|")select au)
));
Back to the drawing board.
OTHER TIPS
I'm not sure if this could possibly work, but maybe try to use join of List<int> IDs
and MyEntities entities
?
You can't.
What does CompiledQuery
do? It pre-converts the query to a canonical command tree -- an intermediate representation used to generate SQL by the provider.
The SQL for a command with a scalar param is the same structure regardless of the param value. But the SQL generated for, say, a list of 2 items will be structurally different from the SQL afor a list of 3 items, because it takes one fewer OR
predicate in its WHERE
clause. Most DB servers won't take lists as a param value, after all.
Your string/|
kludge works because you're now passing only one param, not a list, to the DB server. But as you've seen, the server can't index such a query, so it will be slow.