5

I have an object which has a variable length list of items (incomingList in code example) and a list of people which each have a list of items. I want to return only those people that have all the items in the incomingList.

So looking at the example, I only want person 1 and 3 returned.

The people are in a database and I want to retrieve as little data as possible so I am trying to work out what the linq query needs to be to achieve this? If I knew the length of the incomingList was always going to be the same I could do "...Any(..) && ...Any(...) &&" etc - but the length will vary.

void Main()
{
    var incomingList = new IncomingItem();

    var matchItem1 = new MatchItem { ItemType = "objectId", ItemValue = "60" };
    var matchItem2 = new MatchItem { ItemType = "area", ItemValue = "CU" };

    incomingList.MatchList = new List<MatchItem>();
    incomingList.MatchList.Add(matchItem1);
    incomingList.MatchList.Add(matchItem2);

    var people = new List<Person>();

    var person1 = new Person { Id = 1 };
    person1.ListOfItems = new List<Item>();
    person1.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "60" });
    person1.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "1" });
    person1.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "30" });
    person1.ListOfItems.Add(new Item { ItemType = "area", ItemValue = "CO" });
    person1.ListOfItems.Add(new Item { ItemType = "area", ItemValue = "CU" });
    people.Add(person1);

    var person2 = new Person { Id = 2 };
    person2.ListOfItems = new List<Item>();
    person2.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "60" });
    people.Add(person2);

    var person3 = new Person { Id = 3 };
    person3.ListOfItems = new List<Item>();
    person3.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "60" });
    person3.ListOfItems.Add(new Item { ItemType = "area", ItemValue = "CU" });
    people.Add(person3);

    var person4 = new Person { Id = 4 };
    person4.ListOfItems = new List<Item>();
    person4.ListOfItems.Add(new Item { ItemType = "objectId", ItemValue = "12" });
    people.Add(person4);
}

public class IncomingItem
{   
    public IList<MatchItem> MatchList { get; set; }
}

public class MatchItem
{
    public List<object> SomeMoreInformation { get; set; }

    public string ItemType { get; set; }

    public string ItemValue { get; set; }
}

public class Person
{
    public int Id { get; set; }

    public IList<Item> ListOfItems { get; set; }
}

public class Item
{
    public int Id { get; set; }

    public int PersonId { get; set; }

    public string ItemType { get; set; }

    public string ItemValue { get; set; }
}
Lianne Crocker
  • 141
  • 1
  • 10

1 Answers1

2

This returns all people that have all items of incomingList in their ListOfItems:

var result = people.Where(p => incomingList.MatchList
                       .All(l => p.ListOfItems.Select(loi => new { loi.ItemType, loi.ItemValue })
                           .Contains(new { l.ItemType, l.ItemValue }) ));

Anonymous types should have properties with equal names and types to resolve to "equal", which condition is met in this case.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Thank you, this is working but I can't work out why it is when it doesn't reference both properties, what am I missing? – Lianne Crocker Jun 09 '16 at 13:46
  • No, it should be matching on both ItemValue and ItemType, rather than just ItemValue. (Which your solution appears to do, but I can't see how!) – Lianne Crocker Jun 09 '16 at 13:49
  • Whilst this works on the example it doesn't work when moved to my main code. I get an EF error : Unable to create a constant value of type 'DTO.MatchListIten'. Only primitive types or enumeration types are supported in this context. DTO.MatchListItem is not a database entity, Person and Item are. – Lianne Crocker Jun 09 '16 at 14:21