我正在尝试使用EF 7查询集合和子集合。这是代码:
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address.Where(p => p.AddressTypeID == 1))
.ThenInclude(p=> p.City)
.ToListAsync();
> Error CS1061 'IEnumerable<Address>' does not contain a definition for
> 'City' and no extension method 'City' accepting a first argument of
> type 'IEnumerable<Address>' could be found (are you missing a using
> directive or an assembly reference?) Contacts.DNX 4.5.1, Contacts.DNX
> Core 5.0
当我使用
时,它工作正常var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address)
.ThenInclude(p=> p.City)
.ToListAsync();
但是这将加载客户的所有地址,我只想要AddressTypeID为1的最近地址。
知道怎么做吗?
答案 0 :(得分:2)
您可以尝试anonymous projection,它会将您的查询转换为SQL。
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID)
.Select(cntct=> new
{
contact = cntct,
address = cntct.Address.Where(p => p.AddressTypeID == 1),
city = cntct.Address.Where(p => p.AddressTypeID == 1)
.Select(h=>h.City),
}.ToList();
答案 1 :(得分:1)
您无法在“包括”中进行过滤。在任何版本的实体框架中。
如果你需要加载集合的一个子集,那么你需要加入而不是使用导航属性和过滤器,只要你需要使用Where子句
像这样(可读性的简化,额外步骤):
var filteredAddresses = Addresses.Where(x=>x.AddressTypeId==1);
var customersWithAddress = Customers.Join(filteredAddresses, x=>x.Id,x=>x.CustomerId,(c,a)=> new {
Customer=c,
Address=a
});
或者如果您需要单个客户,假设您在地址中有客户导航属性:
var addressWithCustomer = Addresses
.Where(x=>x.AddressTypeId==1 && x.CustomerId == customerId)
.Include(x=>x.Customer)
.Include(x=>x.City)
.Single();
答案 2 :(得分:0)
很多时候,最好是处理涉及条件嵌套实体的查询,从嵌套实体开始,将条件应用于此嵌套伙伴,然后将父实体投射出来,因为它总是更容易到达嵌套可枚举的父实体。 (多对一)
在我们的例子中,我们可以在Address实体上应用过滤器,然后将其分组到Contact实体上。
var customerID = 86795;
var query = await _context.Addresses
.Where(a => a.Contact.CustomerID == customerID
&& a.Contact.RegistrationDate.Year == 2016
&& a.AddressTypeID == 1)
.Include(a => a.Contact)
.Include(a => a.City)
.GroupBy(a => a.Contact)
.Take(20) // by the way, you should apply some orderby for a predicatble Take
.ToListAsync();
如果你绝对想要一个联系人列表作为上述查询的输出,你可以这样做。
var contacts = query.Select(g =>
{
g.Key.Addresses = g.ToList();
return g.Key;
}).ToList();
// now you can work off the Contacts list, which has only specific addresses
这基本上会为您提供所有具有CustomerID的联系人的分组列表,以及这些地址类型和注册年份。这里重要的是遍历组以获取地址,而不是使用grouping.Key.Addresses导航。 (grouping.Key将是Contact实体)
此外,我不知道CustomerID是否是Contact实体的主键,但如果是,则看起来您只需要一个联系人的匹配地址列表。在这种情况下,查询将是:
var query = await _context.Addresses
.Where(a => a.Contact.CustomerID == customerID && a.AddressTypeID == 1)
.Include(a => a.Contact)
.Include(a => a.City)
.ToListAsync();
答案 3 :(得分:0)
包含Eager Load的集合,然后使用Any而不是Where ...来选择所需实体的子项中的特定项目。
var customerID = 86795;
var query = await _context.Contacts
.Where(g => g.CustomerID == customerID )
.Include(g => g.Address.Any(p => p.AddressTypeID == 1))
.ThenInclude(p=> p.City)
.ToListAsync();