在Entity Framework中正确使用“using”语句的方法

3
我有一些关于使用 using 语句的问题。我了解它的作用(如果我理解正确,它会销毁所有打开的连接等),但我不确定应该如何正确使用它。
我正在处理的项目中不包含任何存储库,而这对于 Entity Framework 是不需要的。
所以基本上,在我的方法中,我将获得一组 Guids 作为参数。这些 id 是餐厅的 id,并且我想检索在这些餐厅上给出的所有评论。
所以目前,我是这样检索列表的:
public void DoSomething(List<Guid> restaurantIds)
{
    List<Review> reviews;
    using (var db = new Context())
    {
        reviews = db.Reviews.Where(x => restaurantIds.Contains(x.RestaurantId)).ToList();
    }
    //More stuff here
}

这是在using语句之外声明列表的常见不良做法吗?我想到了一些替代方案,但我仍然不确定哪个更好。
  1. 在同一类中创建一个单独的方法,执行此操作并返回该列表。这样,在我的DoSomething方法中,我可以像这样使用它:List<Review> reviews = GetReviewsFromRestaurants(restaurantIds);
  2. 我必须先创建上下文,然后在不使用using块的情况下使用LINQ语句。完成后,我必须调用.Dispose()
像我示例中使用using语句有问题吗?如果有,那么替代方案是否更好?如果没有问题,您能否给我一个检索此列表的示例?

你能详细说明一下你所谓的不良实践是什么吗?是指在using语句之外声明变量吗? - Renatas M.
好的,我会在我的帖子里添加它。 - user4189129
1
这本身并不是一个坏的做法,但如果在上下文被释放后尝试延迟加载导航属性,则可能会出现问题。 - Mat J
只要你调用.ToList(),这应该不会成为问题,对吧?我知道延迟加载,所以每次从数据库检索数据时都会确保调用.ToList() - user4189129
1
@RandomStranger - 你提到在同一个方法中有多个击中点,将我的using代码块扩展到整个方法是否会有问题?- 这应该没问题 || 只要您调用“.ToList()”,这就不会有问题,对吗?- 不对。假设您的“Review”实体具有未预加载的“SomeRelationalEntity”,并且在尝试从您获得的列表中访问“SomeRelationalEntity”时(即使在执行“ToList()”后),EF将会为您命中数据库并获取它(延迟加载)_如果在同一上下文中发生_。 - Developer
显示剩余3条评论
3个回答

3

在这种情况下,大括号定义了它们自己的作用域。你在大括号外声明的变量将在大括号内可见,这是可以的。

实际上,这是try catch块的速记形式。

List<Review> reviews;
var db = new Context();
try
{
   reviews = db.Reviews.Where(x => restaurantIds.Contains(x.RestaurantId)).ToList();
}
finally
{
  db.Dispose();
} 

你的代码比这个更简洁。编译器将始终调用“已使用”的对象上的.Dispose


2
关于变量reviews,我认为在using块外声明它并不是什么坏事。
推荐使用分离方法。实际上,您仍然可以使用一个存储库类(RestaurantRepository)来处理所有这些基本操作,如:根据单个或多个标识符获取所有餐厅、创建新餐厅、更改餐厅的某些数据等。
这样可以确保将业务逻辑与基本操作分离。 可释放的上下文 vs. 显式Dispose()。可释放的上下文显然更好,因为即使您的代码失败,也会确保调用Dispose()。
更大的视角——Entity framework 和 context dispose 这已经在这里讨论过了。此外,这篇文章表明dispose并不像看起来那么必要。
就我个人而言,我一直在使用“工作单元模式”来允许多个更改(在各种存储库/实体上),并且由于没有释放上下文而没有遇到麻烦。

是的,我同意使用代码库。问题是,我所在的团队并不赞同,作为一名实习生,我的决定权很小。 - user4189129
这不是为了仓储模式,而是为了将基本操作分开以获得清晰的代码和可重用性。DoSomething 同时执行过滤和“某事”。如果其他方法想要在一些经过筛选的评论列表上做其他事情,它就必须自行进行筛选。 - Alexei - check Codidact
啊,我明白了,所以我不是特别需要一个存储库,但在这个类中创建一个单独的方法是一个好的实践? - user4189129
是的,其他方法也可以。 - Alexei - check Codidact
有点跑题了。因为这个答案似乎是最完整的。我想指出一些事情。我在公司使用Azure时看到过这种使用“using”并在完成数据库查询后立即释放连接的模式。因为一段时间以前(我不知道现在是否仍然是这样),开放的连接会影响公司支付的价格。 - Razvan Dumitru

0
通常没有“什么是不好的做法”的通用答案,你的问题也不例外。虽然有时会有明显的不良实践和显然的良好实践,但有很多因素会影响你的决策(例如你的要求、组织规则或团队经验等)。
在 Entity Framework 中,你可以保持上下文的存在时间比只有一瞬间更长(尽管保持它的存在时间过长可能也不是一个好主意),只要你确保在最后释放它即可。但是,以这种方式应用“using”到你的上下文中也没有任何问题。在 Web 应用程序中,上下文通常只被使用很短的时间,并且低级别的连接池通常仍然保持解决方案的高性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接