C# 实体框架、linq函数和内存使用

C# 实体框架、linq函数和内存使用,c#,entity-framework,linq,C#,Entity Framework,Linq,我是EF的新手,我曾经处理过数据集、表适配器和存储过程。我刚刚发现了EF的简单性,我发现EF方法对我的发展有很大帮助。我几乎没有问题,我试图寻找他们的答案,但徒劳无功。由于我总是与拥有大型表的客户一起工作,因此我打这个电话的事实例如: _ordersContext.Services.ToList() 这是否意味着整个服务表被加载到内存中?如果答案是肯定的(顺便说一下,我认为答案是肯定的),我们可以通过使用linq函数来避免内存开销吗?例如Take()方法?(我的意思是,如果只想有10条记录,而

我是EF的新手,我曾经处理过数据集、表适配器和存储过程。我刚刚发现了EF的简单性,我发现EF方法对我的发展有很大帮助。我几乎没有问题,我试图寻找他们的答案,但徒劳无功。由于我总是与拥有大型表的客户一起工作,因此我打这个电话的事实例如:

_ordersContext.Services.ToList()

这是否意味着整个服务表被加载到内存中?如果答案是肯定的(顺便说一下,我认为答案是肯定的),我们可以通过使用linq函数来避免内存开销吗?例如Take()方法?(我的意思是,如果只想有10条记录,而不将整个表加载到内存中)。关于其他linq函数的相同问题,如where、first、firstordefault、count等。。。我的意思是,我们必须加载整个表吗?是否有关于如何在最佳实践和内存使用方面使用EF的良好文档。

是的,如果调用
\u ordersContext.Services.ToList()
它将加载整个表,是的,您可以使用LINQ方法查询数据库并仅检索所需的记录


查看MSDN上的此链接:

是。整个表将被加载到内存中。对ToList()的调用将立即执行查询,在本例中,该查询是整个表

ToList(),ToArray(),。。。函数将返回列表

FirstOrDefault将返回最多一项

SingleOrDefault将返回最多一项,如果结果超过1项,则引发异常

有关ef、linq和延迟执行的完整说明,请参见此处

在调用ToList()之前,没有加载任何服务,但是第一次调用ToList()EF将加载整个服务,因此为了避免加载所有服务,请先查询服务以获取所需内容,调用Skip、Take、Where或其他服务,EF将生成一个查询,其中加载获取所需的确切服务

查看MSDN。如果您发现延迟的术语,您就知道此方法不会执行查询,并且可以与其他方法链接。只有那些不使用延迟执行的才会开始处理查询并将结果加载到内存中

还请记住,您可以使用
AsEnumerable()
强制
Linq到对象
,而无需将所有内容加载到内存中。这将把查询转换成sql,执行数据库查询,并将结果流到内存中

所以你可以这样做:

var orderList = _ordersContext.Services
    .Where(x => somecondition)
    .OrderBy(x => x.Column)
    .AsEnumerable() // after this you can use any .NET method since it doesnt need to be translated to sql
    .Where(x => complex filter not supported by Linq-To-Entities)
    .Take(10)
    .ToList()
这仍然只会将10条记录加载到内存中,并使用数据库引擎(预)筛选或排序,但允许使用Linq to实体不支持的.NET方法

相关的:

通常,返回序列的方法使用延迟执行和 返回单个对象的方法不会返回


例外情况是返回集合的方法,如
ToList
ToArray
ToLookup
ToDictionary
,这些方法不使用延迟执行。

关于第一个问题,是的,这将把数据库中的所有记录加载到客户端。 在处理包含大量记录的表时,如您所述,您可以使用
.Skip(()=>…)
Take(()=>…)

关于内存和其他linq epxResion,如。Where、SingleOrDefault、FirstOrDefault等。。。从查询表达式到SQL查询的转换有一定的开销,但EF已经缓存了这些查询,并在可能的情况下重用和解析查询。所以情况并没有那么糟

关于查询表达式和有关查询表达式的更多信息,您可以查看:

关于EF的更多信息,请点击此处

关于EF查询性能

EF将缓存查询并重用它们,正如我已经提到的

还创建存储过程并使用它们代替原始sql查询。使用SQL Server Profiler可以很容易地观察到这一点

关于数据库上下文性能 DbContext的一个好处是ChangeTracker,它将跟踪其生命周期内的任何实体更改(直到被处置),如果您计划对特定实体进行一些修改/更新,这是可以的,但是当您进行“只读”查询时,您可以稍微优化上下文

DbContext
具有具有以下设置的。
Configuration
属性

AutoDetectChangesEnabled
启用/禁用更改跟踪

LazyLoadingEnabled
启用/禁用导航属性的延迟加载。 有关延迟加载的详细信息:

ProxyCreationEnabled
启用/禁用实体运行时包装的创建。这与实体中的导航属性有关。在访问启用LazyLoading EF的.Firends属性时,如果您具有一对多的关系(比如有许多朋友的人),很快就会将此转换为JOIN查询,并将获取和具体化当前实体的所有朋友,这是可能的,因为代理类会覆盖.friends属性行为

因此,当您仅执行只读查询时,可以禁用这些设置。请记住,禁用懒散加载将导致导航属性未具体化。要解决此问题,必须在原始查询中加入/包括这些查询

这可以通过使用此处描述的一些方法来实现:

关于查询具体化 您已经发现了两种可能的方法。 使用.ToList()或使用Skip and Take分页

您还可以
foreach
创建SQL游标的查询

有关查询具体化的详细信息:

这是一些总体提示。此外,你可以查看文章中的链接,我认为它们是很好的链接