实体框架,linq函数和内存使用

时间:2017-01-26 14:36:49

标签: c# entity-framework linq

我是EF新手,我曾经使用数据集,表适配器和存储过程。我刚刚发现EF的简单性,我发现EF方法可以帮助我很多我的发展。我有几个问题,我试图寻找他们的答案但是徒劳无功。由于我总是与拥有巨大的表的客户合作,所以我打电话的例子如下:

_ordersContext.Services.ToList()

是否意味着将整个Services表加载到内存中?如果答案是肯定的(我认为答案是肯定的),我们可以通过使用linq函数来避免内存成本吗?例如Take()方法? (我的意思是,如果你想只有10条记录,没有将整个表加载到内存中)。关于其他linq函数的相同问题,比如where,first,firstordefault,count等...我的意思是,我们是否必须加载整个表?是否有一个很好的文档讨论如何使用EF在最佳实践和内存使用方面。

5 个答案:

答案 0 :(得分:3)

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

另请注意,您可以强制使用Linq-To-Objects,而无需使用AsEnumerable()将所有内容加载到内存中。这会将您的查询转换为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-Entities不支持的.NET方法。

相关:

Linq - What is the quickest way to find out deferred execution or not?

  

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

例外是返回集合的方法,例如ToListToArrayToLookupToDictionary,它们不会使用延迟执行。

答案 1 :(得分:2)

是。整个表格将被加载到内存中。您对ToList()的调用将立即执行查询,在这种情况下是整个表。

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

FirstOrDefault最多会返回一个项目

如果结果超过1项,SingleOrDefault将返回一个项目并抛出异常。

请参阅此处以获取有关ef,linq和延迟执行的完整说明

https://blogs.msdn.microsoft.com/charlie/2007/12/10/linq-and-deferred-execution/

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

关于内存和其他linq epxresions,如.Where,SingleOrDefault,FirstOrDefault等......从查询表达式到SQL查询的转换有开销,但是EF已经缓存了这些内容并重新使用和解析了查询能够。所以它并没有那么糟糕。

回合查询表达式以及有关它们的更多信息,您可以查看http://www.tutorialsteacher.com/linq/linq-tutorials

关于EF更多http://www.entityframeworktutorial.net/

关于EF查询效果

EF将缓存查询并重复使用它们,如我已经提到的那样。

还创建存储过程并使用它们而不是RAW sql查询。使用SQL Server Profiler

可以很容易地观察到这一点

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

DbContext具有。Configuration属性,并具有以下设置。

AutoDetectChangesEnabled启用/停用更改跟踪

LazyLoadingEnabled启用/禁用延迟加载导航属性。 有关延迟加载的更多信息:http://www.entityframeworktutorial.net/EntityFramework4.3/lazy-loading-with-dbcontext.aspx

ProxyCreationEnabled启用/禁用为实体创建运行时包装器。这与您实体中的导航属性有关。很简单当你有一对多的关系(让很多朋友说话的人)在访问启用了LazyLoading EF的.Firends属性时,会将其转换为JOIN查询并获取并实现当前实体的所有朋友,这是可能的,因为代理类覆盖.Friends属性行为。

因此,当您只执行只读查询时,您可以禁用这些设置。请记住,禁用LazyLoading将导致未实现导航属性。要解决此问题,您必须加入/包含原始查询中的那些。

可以使用此处描述的一些方法进行调整:https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

关于查询实现 你已经发现了两种可能的方法。 使用.ToList()或使用Skip和Take

分页

您还可以foreach创建 SQL CURSOR 的查询。

有关查询实现的更多信息: https://msdn.microsoft.com/en-us/library/bb738633(v=vs.110).aspx

这是一些整体提示。此外,您可以查看帖子中的链接,我认为它们是一个很好的起点。

<强>要点: 根据我的经验,ORM非常适合新项目,因为它们易于修改,可以与更多团队成员联系(更接近C#然后是SQL)。但最终部分查询在SQL中被重写主要是因为从服务器运行sp仍然更快,而EF有时会创建最复杂的查询,最好避免。

答案 4 :(得分:0)

是的,如果你调用_ordersContext.Services.ToList()它将加载整个表,是的,你可以使用LINQ方法查询数据库并只检索你需要的记录。

在MSDN上查看此链接:https://msdn.microsoft.com/en-us/library/bb399367(v=vs.110).aspx