C# 在LINQ中对子表使用WHERE子句

C# 在LINQ中对子表使用WHERE子句,c#,linq,entity-framework-core,C#,Linq,Entity Framework Core,在我的客户型号中,我有 public virtual ICollection<AddressModel> AddressIDs { get; set; } 按姓氏限制返回的数据集 我正在尝试添加在地址中搜索邮政编码的功能。通过各种链接,它可以在VisualStudio中工作,但在执行时会中断 CustomerList = CustomerList .Include(ps => ps.AddressIDs .Where(a =&

在我的
客户
型号中,我有

public virtual ICollection<AddressModel> AddressIDs { get; set; }
按姓氏限制返回的数据集

我正在尝试添加在地址中搜索邮政编码的功能。通过各种链接,它可以在VisualStudio中工作,但在执行时会中断

CustomerList = CustomerList
    .Include(ps => ps.AddressIDs
                     .Where(a => a.Postcode == postcodeToSearchFor));
带着错误

InvalidOperationException: The property expression 'ps => {from AddressModel a in ps.AddressIDs where ([a].Postcode == __p_0) select [a]}' is not valid. The expression should represent a property access: 't => t.MyProperty
如何将
Where
子句添加到子表上的LINQ中

编辑
无论是谁提出的答案,这个问题显然与一个表有关,而我明确询问的是子表。

您不能在Include中使用where语句。您可以通过以下单个linq查询获得所需:

var CustomerList = _context.Customers.Where(ps =>
    ps.Surname.Contains(surnameToSearchFor) 
    && ps.AddressIDs.Any(ad => ad.Postcode == postcodeToSearchFor ));
正如前面提到的另一个答案(渐进式),您无法在
包含中进行筛选

另一个答案(渐进式)可能是你的解决方案,也可能不是。它将为您提供在邮政编码中至少有一个地址的所有客户,但随后它将加载客户的所有地址(包括不同邮政编码中的地址)

如果您只想检索邮政编码的地址,那么就写下这个答案,我怀疑就是这样。如果您只希望检索客户并仅对其地址进行筛选(但不加载地址),则另一个答案(通过渐进方式)是解决方案


正如我所说,你不能通过包含来实现。但是,还有其他解决方案:

1。查找地址并包括客户。

而不是查找客户并包括他们的地址

 var addresses = _context.Addresses
                         .Include(a => a.Customer)
                         .Where(a =>
                              a.Postcode == postcodeToSearchFor
                              &&
                              a.Customer.Surname.Contains(surnameToSearchFor))
                     .ToList();
您仍然可以通过以下方式获得客户列表:

var customer = addresses.Select(a => a.Customer).Distinct();
一般的经验法则是,始终从子级开始查询,并包含其父级,而不是相反。在某些情况下,这并不重要,但在您的特定情况下,这确实很重要,因为您希望避免隐式加载所有子项

2。明确定义结果集

换句话说,使用
Select()

如果您对结果有具体的期望,这将为您提供更多的控制,但它更为冗长,而且(依我看)不如其他解决方案。只有在第一个解决方案不适合您时才使用它

_context.Customers.Where(ps =>
                             ps.Surname.Contains(surnameToSearchFor) 
                             && 
                             ps.AddressIDs.Any(ad => ad.Postcode == postcodeToSearchFor))
                  .Select(ps => new
                                {
                                    Customer = ps,
                                    Addresses = ps.AddressIDs.Where(ad => ad.Postcode == postcodeToSearchFor))
                                })
                  .ToList();
请注意,这里不需要
Include()
Include()
配置隐式加载行为,但您的
Select()
显式加载数据。

尝试以下操作:

var CustomerList = _context.Customers.Where(ps => ps.Surname.Contains("surnameToSearchFor")).Select(ps => new
{
   Surname = ps.Name,
   AddressIDs = ps.AddressIDs.Where(a => a.PostCode == postcodeToSearchFor)
 });

我需要
客户
模型的名字和姓氏,他们有一个特定的地址,所以根据Progressive的回答,我使用了这个

var CustomerList = CustomerList.Where(ps => ps.AddressIDs
      .Any(a => a.Postcode.Contains(postcodeToSearchFor)));

这会带回任何带有邮政编码任何部分的
客户
,但不会带回任何带有空白或
邮政编码的客户。

使用内置方法无法做到这一点。看起来这是一个已知的问题,并且有一个扩展库:请注意,这不会过滤包含的列表。它将为您提供在邮政编码中至少有一个地址的所有客户,但随后它将加载该客户的所有地址,而不管他们的邮政编码是什么。@如果不包含关键字,则它不会加载所有地址。实际上,它还没有加载任何地址(假设op使用了eager加载选项)。但是你的思维方式实际上是对的。我错过了缺少的
Include()
,你是对的。我有点假设OP想要加载地址。我在这个假设下写了一个答案,但如果OP不需要地址,你的答案会更好。你还将加载在
postcodeToSearchFor
中没有任何地址的客户。这可以通过添加以下条件和条件来解决:ps.姓氏.Contains(“姓氏ToSearchFor”)&&ps.AddressIDs.Count>0但这完全取决于您想要什么,如果您想要拥有0个AddressIDs的客户,则需要删除第二个条件。
&&ps.AddressIDs.Count>0
将过滤掉没有任何地址的客户。它不会筛选出在
postcodetosearch for
中有地址但没有地址的客户。ps.lasname.Contains(“namesttosearch”)&&ps.AddressIDs.Where(a=>a.PostCode==postcodetosearch for)。计数>0:)
var CustomerList = CustomerList.Where(ps => ps.AddressIDs
      .Any(a => a.Postcode.Contains(postcodeToSearchFor)));