Reputation: 363
I have the following class:
class document
{
int Id;
List<Tag> Tags;
}
class Tag
{
int Id;
}
I want to get all the documents that have at least one of the tags that the user selects.
I have written the following linq query:
List<int> tagIds = tags.Select (x => x.Id).ToList ();
query.Where (doc => tagIds.Any (x => doc.Tags.Select (y => y.Id).Contains (x)));
If I execute it against a list of documents, it works, but if I execute it against a sqlite database using efcore 5 I get the following error:
System.InvalidOperationException: 'The LINQ expression 'DbSet<DemaDocument>()
.Where(d => __tagIds_0
.Any(x => DbSet<Dictionary<string, object>>("DemaDocumentDemaTag")
.Where(d0 => EF.Property<Nullable<int>>(d, "Id") != null && object.Equals(
objA: (object)EF.Property<Nullable<int>>(d, "Id"),
objB: (object)EF.Property<Nullable<int>>(d0, "DocumentsId")))
.Join(
inner: DbSet<DemaTag>(),
outerKeySelector: d0 => EF.Property<Nullable<int>>(d0, "TagsId"),
innerKeySelector: d1 => EF.Property<Nullable<int>>(d1, "Id"),
resultSelector: (d0, d1) => new TransparentIdentifier<Dictionary<string, object>, DemaTag>(
Outer = d0,
Inner = d1
))
.Select(ti => ti.Inner.Id)
.Any(p => p == x)))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
How can I rewrite the query using fluent LINQ so that it will work? Is it possible, or do I have to retrieve the documents in memory and then run the query? This would not be ideal, because the documents will grow over time...
Thanks in advance
Upvotes: 0
Views: 1658
Reputation: 36729
.Contains
should be translated as a SQL IN
statement, i.e. x IN 1, 2, 3
. This requires the list to be constant. In your example doc.Tags.Select (y => y.Id)
is unique for each document, so it cannot be translated to a constant list.
What you are doing is more or less checking if two lists intersects, so we should be able to reverse the order of the two lists:
query.Where(doc => doc.Tags.Any(x => tagIds.Contains(x.Id)))
Now the tagIds is constant for the query, and the .Contains
statement can be properly translated.
Upvotes: 3