在我们针对全新项目的EF实现中,我们在Repository中有GetAll方法。但是,随着我们的应用程序的增长,我们将要说5000产品,一路走来,将是性能问题。不是吗?
如果是这样,解决这个未来问题的好方法是什么?
任何帮助都将得到高度赞赏。
答案 0 :(得分:3)
如果get all枚举集合,则可能会成为性能问题,从而导致整个数据集在IEnumerable
中返回。这一切都取决于连接数,数据集的大小,是否启用了延迟加载,SQL Server的执行方式,仅举几例。
有些人会说这不是理想的,你可以让GetAll()
返回一个IQueryable
,它会推迟查询,直到通过转到SQL来填充集合。这样,您可以使用其他Where()
,Take()
,Skip()
等语句过滤结果,以便进行分页,而无需从数据库中检索所有5000多种产品。
答案 1 :(得分:1)
这取决于您的存储库类的设置方式。如果您立即执行查询,即如果您的GetAll()
方法返回IEnumerable<T>
或IList<T>
之类的内容,那么是的,这可能很容易成为性能问题,您通常应该避免除非你真的想一次加载所有记录,否则就会发生一些事情。
另一方面,如果您的GetAll()
方法返回IQueryable<T>
,则可能根本没有问题,具体取决于您是否信任撰写查询的人。返回IQueryable<T>
将允许调用者在实际生成SQL代码之前进一步细化搜索条件。性能方面,如果使用您的代码的开发人员在执行查询之前未应用任何过滤器,那么这只会是一个问题。如果你足够信任它们给它们足够的绳索来挂起它们(并且可能会降低你的数据库性能),那么只返回IQueryable<T>
可能就足够了。
如果您不信任它们,那么,正如其他人所指出的那样,您可以使用Skip()
和Take()
扩展方法来限制查询返回的记录数,以实现简单的分页,但请注意,如果人们在进入下一页之前对数据库进行了更改,则记录可能会漏掉。与不断变化的数据库无缝地进行分页工作比许多人想象的要困难得多。
另一种方法是将GetAll()
方法替换为需要调用者在返回结果之前应用过滤器的方法:
public IQueryable<T> GetMatching<T>(Expression<Func<T, bool>> filter)
{
// Replace myQuery with Context.Set<T>() or whatever you're using for data access
return myQuery.Where(filter);
}
然后像var results = GetMatching(x => x.Name == "foo");
一样使用它,或者你想做什么。请注意,通过调用GetMatching(x => true)
可以轻松绕过这一点,但至少可以明确这一意图。您还可以将其与第一种方法结合起来,对返回的记录数量设置一个固定上限。
我个人的感觉是,所有这些限制查询的方法都只是针对不良开发人员开始使用您的应用程序的保险,如果您的项目开发人员不好,他们会找到一种方法来解决问题。无论你想做什么都会出现问题。所以我的投票只是返回一个IQueryable<T>
并相信它会被负责任地使用。如果有人滥用它,请删除GetAll()
方法并为其提供训练轮方法,例如GetRecentPosts(int count)
或GetPostsWithTag(string tag, int count)
或类似的方法,其中查询逻辑不在他们手中。
答案 2 :(得分:0)
您所指的是分页,通过Skip / Take方法使用LINQ非常简单。
EF查询被延迟加载,这意味着它们在评估之前不会实际访问数据库,因此以下内容只会在跳过前10行后拉出前10行
context.Table.Skip(10).Take(10);
答案 3 :(得分:0)
改善这种情况的一种方法是使用分页
context.Products.Skip(n).Take(m);