Linq to Entities - 过滤属于另一个列表的一个列表中的任何项目
Linq to Entities - Filter on any item in one list belonging to another list
这是我的场景。我有一个文档 class。该文档通过多对多关系与一个 DocumentClasses table 关联,因此一个文档可以有一个或多个 class。当 运行 搜索时,用户可以选择按 class 过滤文档。因此,如果用户选择 select 任何 classes,我需要能够在我的查询中附加一个 where 子句。其逻辑是,如果文档被分配给用户 selected 的 classes 中的任何 classes,则文档应该被 returned。所以伪代码中需要的基本查询。所以基本上,如果列表 A 中的任何数字属于列表 B,则 return 记录。
我试过了(RestrictByClasses 只是一个列表(整数)):
query = query.where(Function(resultItem) RestrictByClasses.Contains(resultItem.DocumentClassIds.Any())
但我得到以下异常:
The nested query is not supported. Operation1='Case' Operation2='Collect'
有没有办法让linq像这样过滤掉记录?
谢谢!
更新:
在进行了更多的调试之后,我认为更多的是与我如何投影到对象上以便加载可用于过滤的值有关。这是我进行投影的方式:
Dim query = From document In dbContext.Documents
Select New FeeAndReceptionReportIntermediateItem With
{
.BookTypeId = If(restrictByBookTypes AndAlso document.DocumentInstruments.Any(), document.DocumentInstruments.FirstOrDefault().Instrument.BookTypeId, Nothing),
.CustomerId = document.CustomerId,
.DocumentClassIds = If(restrictByDocumentClasses, document.DocumentClasses.Select(Function(group) group.ClassId), Nothing),
.DocumentId = document.DocumentId,
.DocumentNumber = document.DocumentNumber,
.DepartmentId = document.DepartmentId,
.InstrumentGroupIds = If(restrictByInstrumentGroup, document.DocumentInstruments.FirstOrDefault().Instrument.InstrumentGroups.Select(Function(group) group.InstrumentGroupId), Nothing),
.RecordDateTime = document.RecordDateTime,
.RestrictedInstrument = (includeRestrictedDocuments AndAlso document.DocumentInstruments.Any() AndAlso document.DocumentInstruments.FirstOrDefault().Instrument.Restricted)
}
我认为它在抱怨如何将 .DocumentClassIds 和 .InstrumentGroupId 加载到 POCO 对象 (FeeAndReceptionReportIntermediateItem) 中。我真的很想在调用 .ToList() 之前在初始查询中加载这些,如果用户没有传递要求我创建连接的限制,我什至不想做连接,这就是为什么我在加载这些集合时使用导航属性和 if 语句的原因,因为我假设如果 "restrictByDocumentClasses" 为假,则不会访问导航 属性 并且不会包含连接.
这是一种通用模式。第一行从 DbSet<> 获取 IQueryable<>。 select 为我们做了这件事,这样我们就可以在构建查询时继续重用查询来保存我们的查询。然后继续添加 If...Then...query=query.Where(...)...Endif 以继续削减结果集。
var query=db.MyTable.Select(x=>x);
if (RestrictByClasses.Any())
query=query.Where(r =>
r.DocumentClasses.Select(x=>x.ClassId)
.Intersect(RestrictByClasses)
.Any());
if (RestrictBySomethingElse)
query=query.Where(x=>SomethingElse)
我认为这相当于 VB.NET:
Dim query = db.MyTable.[Select](Function(x) x)
If RestrictByClasses.Any() Then
query = query.Where(Function(r) r.DocumentClasses.Select(Function(group) group.ClassId).Intersect(RestrictByClasses).Any())
End If
'Repeat as necessary
If RestrictBySomethingElse Then
query = query.Where(Function(x) SomethingElse)
End If
'End repeat
' Rest here is pseudo code
' Sort
SELECT/SWITCH sortonfield
CASE 'name': query=query.OrderBy(Function(x) x.name)
CASE 'dob': query=query.OrderBy(Function(x) x.dob)
DEFAULT: query=query.OrderBy(Function(x) x.id)
END CASE
'Paginate
query=query.Skip((pagenumber-1)*pagesize).Take(pagesize)
'Project
Dim finalresult=query.Select(Function(x) new something {
name=x.Name,
id=x.id,
things=x.things
});
一旦所有过滤器都已就位(以及可选的排序和分页),然后将结果集投影到您需要的任何内容中。
这是我的场景。我有一个文档 class。该文档通过多对多关系与一个 DocumentClasses table 关联,因此一个文档可以有一个或多个 class。当 运行 搜索时,用户可以选择按 class 过滤文档。因此,如果用户选择 select 任何 classes,我需要能够在我的查询中附加一个 where 子句。其逻辑是,如果文档被分配给用户 selected 的 classes 中的任何 classes,则文档应该被 returned。所以伪代码中需要的基本查询。所以基本上,如果列表 A 中的任何数字属于列表 B,则 return 记录。
我试过了(RestrictByClasses 只是一个列表(整数)):
query = query.where(Function(resultItem) RestrictByClasses.Contains(resultItem.DocumentClassIds.Any())
但我得到以下异常:
The nested query is not supported. Operation1='Case' Operation2='Collect'
有没有办法让linq像这样过滤掉记录?
谢谢!
更新:
在进行了更多的调试之后,我认为更多的是与我如何投影到对象上以便加载可用于过滤的值有关。这是我进行投影的方式:
Dim query = From document In dbContext.Documents
Select New FeeAndReceptionReportIntermediateItem With
{
.BookTypeId = If(restrictByBookTypes AndAlso document.DocumentInstruments.Any(), document.DocumentInstruments.FirstOrDefault().Instrument.BookTypeId, Nothing),
.CustomerId = document.CustomerId,
.DocumentClassIds = If(restrictByDocumentClasses, document.DocumentClasses.Select(Function(group) group.ClassId), Nothing),
.DocumentId = document.DocumentId,
.DocumentNumber = document.DocumentNumber,
.DepartmentId = document.DepartmentId,
.InstrumentGroupIds = If(restrictByInstrumentGroup, document.DocumentInstruments.FirstOrDefault().Instrument.InstrumentGroups.Select(Function(group) group.InstrumentGroupId), Nothing),
.RecordDateTime = document.RecordDateTime,
.RestrictedInstrument = (includeRestrictedDocuments AndAlso document.DocumentInstruments.Any() AndAlso document.DocumentInstruments.FirstOrDefault().Instrument.Restricted)
}
我认为它在抱怨如何将 .DocumentClassIds 和 .InstrumentGroupId 加载到 POCO 对象 (FeeAndReceptionReportIntermediateItem) 中。我真的很想在调用 .ToList() 之前在初始查询中加载这些,如果用户没有传递要求我创建连接的限制,我什至不想做连接,这就是为什么我在加载这些集合时使用导航属性和 if 语句的原因,因为我假设如果 "restrictByDocumentClasses" 为假,则不会访问导航 属性 并且不会包含连接.
这是一种通用模式。第一行从 DbSet<> 获取 IQueryable<>。 select 为我们做了这件事,这样我们就可以在构建查询时继续重用查询来保存我们的查询。然后继续添加 If...Then...query=query.Where(...)...Endif 以继续削减结果集。
var query=db.MyTable.Select(x=>x);
if (RestrictByClasses.Any())
query=query.Where(r =>
r.DocumentClasses.Select(x=>x.ClassId)
.Intersect(RestrictByClasses)
.Any());
if (RestrictBySomethingElse)
query=query.Where(x=>SomethingElse)
我认为这相当于 VB.NET:
Dim query = db.MyTable.[Select](Function(x) x)
If RestrictByClasses.Any() Then
query = query.Where(Function(r) r.DocumentClasses.Select(Function(group) group.ClassId).Intersect(RestrictByClasses).Any())
End If
'Repeat as necessary
If RestrictBySomethingElse Then
query = query.Where(Function(x) SomethingElse)
End If
'End repeat
' Rest here is pseudo code
' Sort
SELECT/SWITCH sortonfield
CASE 'name': query=query.OrderBy(Function(x) x.name)
CASE 'dob': query=query.OrderBy(Function(x) x.dob)
DEFAULT: query=query.OrderBy(Function(x) x.id)
END CASE
'Paginate
query=query.Skip((pagenumber-1)*pagesize).Take(pagesize)
'Project
Dim finalresult=query.Select(Function(x) new something {
name=x.Name,
id=x.id,
things=x.things
});
一旦所有过滤器都已就位(以及可选的排序和分页),然后将结果集投影到您需要的任何内容中。