问题描述
我想知道如何使用 EF6 从 SQL Server 流式传输数据.
I'm wondering how one would go about streaming data from SQL server using EF6.
假设有这些类
- PersonRepository
- EFPerson(EF 模型)
- DomainPerson(域模型)
- PersonUsingClass
假设 PersonUsingClass 依赖于获取一堆 DomainPersons.假设业务规则规定不允许 EFPerson 离开 PersonRepository.
Assume that PersonUsingClass depends on getting a bunch of DomainPersons. Assume that business rules dictate that EFPersons aren't allowed to leave the PersonRepository.
通常我会有一个如下所示的存储库方法:
Normally I'd have a repository method looking like this:
public IEnumerable<DomainPerson> GetPeople()
{
using (var db = new efContext())
{
IQueryable efPeople = db.Person.Where(someCriteria);
foreach (var person in efPeople)
{
yield return person.ToDomainPerson();
}
}
}
使用我这里的代码,所有内容都会在执行 foreach 时加载到内存中.我可以通过将 IQueryable 返回给 PersonUsingClass 来实现流式传输,但这会将 EF 模型暴露给该类,这是不受欢迎的场景.
With the code I have here, everything would be loaded into memory upon doing the foreach. I could achieve the streaming by returning the IQueryable to the PersonUsingClass, but that exposes the EF models to that class, which is an unwanted scenario.
真的不可能隐藏 EF 模型,为什么同时流式传输数据?还是有什么我不知道的?
Is it really impossible to hide away the EF models why streaming data at the same time? Or is there something I don't know?
推荐答案
你创建的方法迭代了一个由 EF 创建的 IQueryable<>
对象.
The method you have created iterates over an IQueryable<>
object that's created by EF.
IQueryable<>
变量已延迟执行,因此在内部,EF 只会在 IQueryable<>
被迭代时调用数据库(即当 .MoveNext()
第一次被调用时).
The IQueryable<>
variable has deferred execution, therefore internally, EF will only make the call to the database when the IQueryable<>
is iterated over (i.e. when .MoveNext()
is first called).
此外,如果您曾经使用 SqlDataReader
手动滚动数据库调用,您会发现可以将查询的结果 .Read()
-by-one,您不需要将所有记录加载到内存中.EF 可能以这种方式流式传输记录(这是我的假设,可能取决于您的特定 EF 设置).
Additionally, if you have ever hand-rolled a database call using SqlDataReader
, you'll see that it is possible to .Read()
results of a query one-by-one, you don't need to load all records into memory. It's likely that the records are being streamed in this way by EF (this is an assumption on my part, it may depend on your specific EF setup).
您的方法正在返回一个 IEnumerable<>
对象,该对象也受到延迟执行的影响.通过调用 GetPeople()
创建它的实例不会导致数据库调用.
Your method is returning an IEnumerable<>
object which is also subject to deferred exeution. Creating an instance of this by calling GetPeople()
will not lead to a database call.
当您的方法的结果被迭代时,您将触发对内部 IQueryable<>
对象的迭代并一一转换结果.
When the result of your method is iterated over, you're then triggering the iteration over the internal IQueryable<>
object and transforming the results one by one.
因此:
在该方法中没有记录被加载到内存中(除非 EF 在内部进行一些缓存).如果您迭代该方法的结果,那么您将逐条迭代每条记录.
No records are being loaded into memory in that method (unless EF is doing some caching internally). If you iterate over the result of that method then you are iterating over each record one by one.
如果您对该方法的结果调用 .ToList()
或 .ToArray()
,则记录将被加载到内存中.
If you call .ToList()
or .ToArray()
on the result of that method then records will be loaded into memory.
这篇关于如何从 LINQ to Entities 查询流式传输数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!