Search code examples
c#sqliteentity-framework-coremany-to-manylinq-to-entities

EntityFrameworkCore.Sqlite - How to query entities with child list containing all items of given list?


Given the following Models

public class ApiImageModel
{
    public int ID { get; set; }
    ...
    public List<TagModel> Tags { get; set; } = new();
}

and

public class TagModel
{
    public int ID { get; set; }
    ...
    public string Name { get; set; }
    public List<ApiImageModel> Images { get; set; } = new();
}

How to query a list of ApiImageModel based on a given set of TagModels using Linq? I am struggling with this for a while now and I'm certainly missing something basic but I can't put a pin on it.

I tried this approach for EF6: EF6 How to query where children contains all values of a list

like so, holding all TagModel-IDs in an array "tagIDs":

int[] tagIDs;
...
IQueryable<ApiImageModel> images = context.Images.Where(image => tagIDs.All(id => image.Tags.Any(tag => tag.ID == id)));

But visual studio rewards me with an "InvalidOperationException":

The LINQ expression 'DbSet<ApiImageModel>()
    .Where(a => __tagIDs_0
        .All(id => DbSet<Dictionary<string, object>>("ApiImageModelTagModel")
            .Where(a0 => EF.Property<Nullable<int>>(a, "ID") != null && object.Equals(
                objA: (object)EF.Property<Nullable<int>>(a, "ID"), 
                objB: (object)EF.Property<Nullable<int>>(a0, "ImagesID")))
            .Join(
                inner: DbSet<TagModel>(), 
                outerKeySelector: a0 => EF.Property<Nullable<int>>(a0, "TagsID"), 
                innerKeySelector: t => EF.Property<Nullable<int>>(t, "ID"), 
                resultSelector: (a0, t) => new TransparentIdentifier<Dictionary<string, object>, TagModel>(
                    Outer = a0, 
                    Inner = t
                ))
            .Any(ti => ti.Inner.ID == id)))' could not be translated. 

I'd be glad for some help :)


Solution

  • Assuming that your tags tagIDs are unique, you can do the following:

    int[] tagIDs;
    var tagCount = tagIDs.Length;
    ...
    var images = context.Images
        .Where(image => image.Tags.Where(tag => tagIDs.Contains(tag.ID)).Count() == tagCount);
    

    Here we use Contains to grab tags in which we are interested and if their Count() is equal to tagIDs.Length - all tags are present in image's Tags relation.