在导航属性上使用Where子句。多对多关系

时间:2018-08-22 17:19:36

标签: c# linq asp.net-core entity-framework-core asp.net-core-2.1

我一直在寻找SO上的其他示例,但仍然无法解决。

我具有以下模型结构

 public class Event
    {
        [Key]
        public int ID { get; set; }
        public ICollection<EventCategory> EventCategories{ get; set; }
    }

 public class Category
    {
        [Key]
        public int ID { get; set; }
        public ICollection<EventCategory> EventCategories{ get; set; }
    }

 public class EventCategory
    {
        [Key]
        public int ID { get; set; }
        public int EventID{ get; set; }
        public Event Event{ get; set; }
        public int CategoryID{ get; set; }
        public Category Category{ get; set; }
    }

在我的事件控制器中,我试图使用LINQ查询来仅显示CategoryID等于1的事件,但我认为我的WHERE子句不断出错。

更新:

我一直在尝试多个查询,但目前是

    var eventsContext = _context.Events
            .Include(e => e.EventCategories)
            .Include(e=>e.EventCategories.Select(ms => ms.Category))
            .Where(e=>e.ID==1)
            .Take(15)
            .OrderByDescending(o => o.StartDate);

这是我得到的错误

Error Messsage

TIA

1 个答案:

答案 0 :(得分:3)

首先,传递给Include的lambda必须是模型表达式。具体来说,这意味着您不能使用类似Select之类的东西。如果您尝试包含EventCategories.Category,则实际上应该这样做:

.Include(e => e.EventCategories).ThenInclude(ms => ms.Category)

这将解决您的即时错误。下一个问题是您尝试查询类别ID的方式不正确。 lamda不会从一个子句延续到下一个子句。换句话说,当您执行Where(e => e.ID == 1)时,eEvent,而不是Category。您仅包含Category的事实并不会将where子句限制为该上下文。因此,您真正需要的是:

.Where(e => e.EventCategories.Any(c => c.CategoryID == 1))

对于它的价值,您也可以将其写为:

.Where(e => e.EventCategories.Any(c => c.Category.ID == 1))

请注意.Category之间的ID。现在,此where子句要求在所有EventEventCategories Category之间进行联接,这意味着您实际上不需要{{ 1}}语句,因为所有这些操作都告诉EF进行与已经进行的相同的JOIN。我仍然通常会显式地执行include,但是,否则,如果您的where子句在将来的迭代中有所更改,那么您可能最终将不再隐式包含实际上想要包含的所有内容。值得深思。