在这种情况下:
public void Delete(int id)
{
using (var connection = GetOpenConnection())
{
connection.Execute($"DELETE FROM MyTable WHERE Id = {id}");
}
}
或者只是:
GetOpenConnection().Execute($"DELETE FROM MyTable WHERE Id = {id}");
我想知道第二种方法是否是减轻维护和简化工作的最佳选择。
答案 0 :(得分:8)
第一个选项使您具有可预测性:GetOpenConnection()
完成后,将从connection.Execute
返回的连接对象立即处理。
另一方面,如果您使用第二种方法,则可以希望将来会在某个时候关闭该连接,但是您完全不确定何时,甚至何时会发生这种连接。 / p>
因此,应该首选第一种方法。
注意:考虑参数化您的查询。即使在您遇到这种情况时,由于id
的类型为id
,在查询中插入int
不会造成威胁,但是在整个代码中始终使用参数是一个好主意。 / p>
答案 1 :(得分:4)
要解决此问题,需要了解Sql Server(和其他数据库)如何使用连接以及ADO.Net如何使用连接池。
数据库服务器往往一次只能处理有限数量的活动连接。这部分与系统上可用的ephemeral ports有限有关,但其他因素也可能起作用。这意味着必须确保始终及时关闭连接,或者确保我们谨慎限制连接的使用,这一点很重要。如果我们希望数据库能够扩展到大量用户,则必须同时进行这两个操作。
.Net通过两种方式解决这种情况。首先,您用于数据库访问(System.Data
和公司)的ADO.Net库包含名为连接池的功能。此功能可以为您合并并缓存连接,以使其有效地根据需要快速打开和关闭连接。该功能意味着您不应在应用程序或会话的整个生命周期内尝试保持共享连接对象处于活动状态。让连接池处理此问题,并为大多数数据库访问创建一个全新的连接对象。 。
解决问题的另一种方法是使用 IDisposable 模式。 IDisposable
通过using
关键字在运行时中提供了直接支持的接口,这样可以确保对象的非托管资源(例如,连接所保持的数据库服务器上的临时端口)是立即清除并以确定性方式清除,即使引发了异常。此功能可确保您由于连接池功能而创建的所有那些短暂连接的寿命确实与所需的一样短。
换句话说,第一个示例中的using块起着重要的作用。忽略它是一个错误。在繁忙的系统上,它甚至可能导致数据库拒绝服务。
您会在问题标题本身中了解到这一点,该标题问道:“哪个对象最好放置?”这两个样本中只有一个完全放置了对象。
答案 2 :(得分:2)
您可以通过这种方式进行设计。
using(var context = new CustomerFactory().Create())
return context.RetrieveAll();
然后在CustomerContext
内部,您将拥有处置逻辑,数据库连接和查询。但是您可以创建继承DbConnectionManager
类,该类将处理连接。但是整个类都将被处置,这也将挽救连接管理器。
public interface ICustomerRepository : IDisposable
{
IEnumerable<Customer> RetrieveAll();
}
public interface ICustomerFactory
{
ICustomerRepository Create();
}
public class CustomerFactory : ICustomerFactory
{
public ICustomerRepository Create() => new CustomerContext();
}
public class CustomerContext : ICustomerRepository
{
public CustomerContext()
{
// Instantiate your connection manager here.
}
public IEnumerable<Customer> RetrieveAll() => dbConnection.Query<Customer>(...);
}
这就是如果您想保留一个表达性调用,这种表达在选项二中表示您的流畅语法,而没有负面影响。