使用Entity Framework多Include筛选数据时遇到的问题
问题分析与解决方案
咱们先来拆解你遇到的两个核心问题:
1. 为什么最初的Where子句会出错?
你第一次尝试的代码:
.Where(Function(y) y.SUBMISSIONS.Select(Function(y) y.XMLBatchNumber = BatchNumber).ToList
有两个明显问题:
- 语法错误:括号没有闭合,最后少了一个
) - 逻辑错误:
y.SUBMISSIONS.Select(...)会返回一个List(Of Boolean)(每个SUBMISSION对应一个是否匹配的布尔值),但Where需要的是单一布尔判断——你要的是这个BATCH下存在至少一个符合条件的SUBMISSION,所以应该用Any而非Select。
2. 为什么Include里加筛选会报错?
EF的Include方法的作用是指定要预加载的导航属性,它只能接受导航属性的路径(比如实体的集合或引用属性),不能在里面加条件判断。你写的Include(Function(x) x.SUBMISSIONS.Select(Function(y) y.XMLBatchNumber = BatchNumber))中,Select返回的是布尔值集合,不是导航属性,所以EF会抛出路径无效的错误。
正确写法分两种场景
场景1:筛选包含符合条件SUBMISSION的BATCH,加载该BATCH所有关联数据
如果你只是想拿到所有**至少有一个SUBMISSION满足XMLBatchNumber = BatchNumber**的BATCH,并且需要加载该BATCH的所有关联数据(包括所有SUBMISSION),只需要修正Where子句:
Dim pl As List(Of BATCH) = db.BATCHes _ .Include("HEADER") _ .Include("SUBMISSIONS") _ .Include("SUBMISSIONS.SUB_HEADER") _ .Include("SUBMISSIONS.MA_POL") _ .Include("SUBMISSIONS.MA_POL.MA_CUR_EMP") _ ' 保留你原来的其他Include语句... .Where(Function(batch) batch.SUBMISSIONS.Any(Function(subm) subm.XMLBatchNumber = BatchNumber)) _ .ToList()
场景2:筛选BATCH,且只加载该BATCH下符合条件的SUBMISSION
如果你不仅要筛选BATCH,还想只加载每个BATCH里满足XMLBatchNumber = BatchNumber的SUBMISSION(而非所有SUBMISSION),需要分EF版本处理:
若使用EF Core 2.1+(支持Filtered Include)
可以直接在Include里加Where过滤关联集合,搭配ThenInclude加载子属性:
Dim pl As List(Of BATCH) = db.BATCHes _ .Include(Function(b) b.HEADER) _ ' 先过滤SUBMISSIONS,再加载它的子属性 .Include(Function(b) b.SUBMISSIONS.Where(Function(s) s.XMLBatchNumber = BatchNumber)) _ .ThenInclude(Function(s) s.SUB_HEADER) _ .ThenInclude(Function(s) s.MA_POL) _ .ThenInclude(Function(p) p.MA_CUR_EMP) _ .ThenInclude(Function(p) p.MA_CON) _ .ThenInclude(Function(p) p.MA_CAD) _ ' 继续添加其他需要的ThenInclude... .Include(Function(b) b.SUBMISSIONS.Where(Function(s) s.XMLBatchNumber = BatchNumber)) _ .ThenInclude(Function(s) s.VEH) _ .ThenInclude(Function(v) v.VEH_GAR_ADD) _ ' 把其他需要过滤的SUBMISSION子属性都用这种方式添加... .Where(Function(batch) batch.SUBMISSIONS.Any(Function(subm) subm.XMLBatchNumber = BatchNumber)) _ .ToList()
若使用EF6(不支持Filtered Include)
EF6没有内置的过滤关联集合方法,需要用投影手动筛选数据:
' 先投影出包含筛选后SUBMISSIONS的匿名类型 Dim projectedData = db.BATCHes _ .Where(Function(b) b.SUBMISSIONS.Any(Function(s) s.XMLBatchNumber = BatchNumber)) _ .Select(Function(b) New With { .Batch = b, .Header = b.HEADER, .FilteredSubmissions = b.SUBMISSIONS _ .Where(Function(s) s.XMLBatchNumber = BatchNumber) _ .Include(Function(s) s.SUB_HEADER) _ .Include(Function(s) s.MA_POL) _ .Include(Function(p) p.MA_CUR_EMP) _ .Include(Function(p) p.MA_CON) _ ' 添加其他SUBMISSION的子属性Include... .Include(Function(s) s.VEH) _ .Include(Function(v) v.VEH_GAR_ADD) _ .ToList() }) _ .ToList() ' 转换成List(Of BATCH)(注意EF6中修改实体集合需附加到上下文) Dim pl As List(Of BATCH) = projectedData.Select(Function(item) item.Batch.SUBMISSIONS.Clear() For Each subm In item.FilteredSubmissions item.Batch.SUBMISSIONS.Add(subm) Next item.Batch.HEADER = item.Header Return item.Batch End Function).ToList()
内容的提问来源于stack exchange,提问作者Optimum8
相关产品推荐
相关产品推荐

