【发布时间】:2013-05-23 19:44:27
【问题描述】:
正如标题所示,我正在寻找一种将 where 子句与包含相结合的方法。
这是我的情况: 我负责支持一个充满代码味道的大型应用程序。 更改太多代码会导致到处出现错误,因此我正在寻找最安全的解决方案。
假设我有一个对象 Bus 和一个对象 People(Bus 有一个导航道具 Collection of People)。 在我的查询中,我需要选择只有醒着的乘客的所有巴士。这是一个简单的虚拟示例
在当前代码中:
var busses = Context.Busses.Where(b=>b.IsDriving == true);
foreach(var bus in busses)
{
var passengers = Context.People.Where(p=>p.BusId == bus.Id && p.Awake == true);
foreach(var person in passengers)
{
bus.Passengers.Add(person);
}
}
在此代码之后,上下文被释放,在调用方法中,生成的总线实体被映射到 DTO 类(实体的 100% 副本)。
此代码会导致多次调用 DB,这是不可行的,所以我找到了这个解决方案 ON MSDN Blogs
这在调试结果时效果很好,但是当实体映射到 DTO(使用 AutoMapper)时,我得到一个异常,即上下文/连接已关闭并且无法加载对象。 (上下文总是关闭不能改变这个:()
所以我需要确保 Selected Passengers 已经加载(导航属性上的 IsLoaded 也是 False)。如果我检查Passengers 集合,Count 也会抛出异常,但是在Passegers 集合上还有一个集合,称为“包装的相关实体”,其中包含我过滤的对象。
有没有办法将这些包装的相关实体加载到整个集合中? (我无法更改自动映射器映射配置,因为它在整个应用程序中使用)。
还有其他获取活跃乘客的方法吗?
欢迎任何提示...
编辑
Gert Arnold 的回答不起作用,因为数据没有立即加载。 但是当我简化它并删除它的加载位置时。这真的很奇怪,因为执行 sql 在这两种情况下都会返回所有乘客。所以把结果放回实体里面肯定有问题。
Context.Configuration.LazyLoadingEnabled = false;
var buses = Context.Busses.Where(b => b.IsDriving)
.Select(b => new
{
b,
Passengers = b.Passengers
})
.ToList()
.Select(x => x.b)
.ToList();
编辑2
Gert Arnold 的工作经过一番挣扎的答案! 正如 Gert Arnold 建议的那样,您需要禁用延迟加载并保持关闭。 这将要求对应用程序进行一些额外的更改,因为上一个开发人员喜欢延迟加载-_-
【问题讨论】:
-
这只是一个用 stackoveflow 编写的示例,没有智能感知:p 现在已修复
-
您能否向我们展示一下该类实现的相关部分对于 Bus、People 和 Passengers 的示例(例如外键和导航属性)?
-
乘客是导航道具耶
-
我有点惊讶这个问题几乎没有受到关注,因为考虑到我很难找到它以及它是如何限制 EF 查询数据库的数据量的好方法。人们没有看到 EF 为数据库运行创建的查询吗?
-
@Ellesedil 你的观点是对的,但是那些“长”的 EF 查询对人类来说只是很长的。它们实际上非常有效。您很难编写一个执行计划比 EF 定期生成的查询更快的查询。
标签: c# entity-framework include where-clause