Question

I need to filter a LINQ query by determining that a parameter passed into a method is in a list. I did something similar to this with another project and it worked fine but I can't get the syntax right here.

First I create a list from a value passed into the method:

// Create a list of category events here
var categoryList = new List<int>();
var categories = context.CategoryEvents
    .Where(c => c.CategoryId == categoryId)
    .Select(c => c.CategoryId);
if(categoryList.Any())
{
    categoryList.AddRange(categories);
}

Next I create my query in which I need to filter the results based on whether the parameter is in the list:

events = context.Events
    .Where(categoryList.Contains(categoryId)) // Doesn't work
Était-ce utile?

La solution

There are a few issues with the code.

  1. You're selecting CategoryId after filtering by CategoryId. Did you mean to select EventIds instead?
  2. if(categoryList.Any()) should be if(categories.Any())
  3. There needs to be a lambda expression in .Where(categoryList.Contains(categoryId))

Here's a revised version of the code that has a better chance of working...

var eventIdList = new List<int>();
var eventIds = context.CategoryEvents
    .Where(c => c.CategoryId == categoryId)
    .Select(c => c.EventId);
if(eventIds.Any())
{
    eventIdList.AddRange(eventsIds);
}

var eventsInCategory = context.Events
    .Where(e => eventIdList.Contains(e.EventId)); // or simply e.Id, depending on what your model looks like

If that works, there is a lot that can be done to improve/simplify the code.

For example, this if block actually executes two database queries, once for Any() and a second one during AddRange()...

if(eventIds.Any())
{
    eventIdList.AddRange(eventsIds);
}

You can actually replace the first chunk of code using ToList(). There is no need for new List<int>(), Any(), or AddRange()...

var eventIdList = context.CategoryEvents
    .Where(c => c.CategoryId == categoryId)
    .Select(c => c.EventId)
    .ToList();

And it sounds like all you're trying to do with this entire piece of code is to find all events in a given CategoryId. You can do this in 1 EF query...

var eventsInCategory = context.Events
    .Join(context.CategoryEvents,
          e => e.EventId, // or simply e.Id, depending on what your model looks like
          ce => ce.EventId,
          (e, ce) => e)
    .ToList();

This can be further simplified if the models are set up with the proper navigation properties. For example, if you have a Categories DbSet and it has a navigation property for all related Events:

var eventsInCategory = context.Categories.Find(categoryId).Events;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top