拥有手动打开和关闭数据库连接的存储库是一种不好的做法吗?
环境:ASP.NET MVC3 C#
假设我有一些存储库(半伪):
public interface IRepository
{
create();read();update();delete();opendb();closedb();
}
public class CarRepository : IRepository
{
private DbContext namedDbContext;
public void opendb()
{
namedDbContext = new DbContext();
}
public void closedb()
{
namedDbContext.dispose();
}
}
然后在控制器中注入存储库并按如下方式使用它来手动控制数据库连接生存期:
public class SomeController : Controller
{
private IRepository CarRepository;
public void SomeController(IRepository _carRepository)
{
CarRepository = _carRepository;
}
public ActionResult SomeAction(int CarId)
{
CarRepository.opendb();
var car = CarRepository.read(CarId);
CarRepository.closedb();
}
}
这是否被认为是不好的做法,因为它正在获取控制权来自存储库的连接并将其放入控制器中?我担心使用依赖注入会导致内存泄漏,并希望确保不会打开重复的连接,也不会长时间运行和未使用。
Environment: ASP.NET MVC3 C#
Say I have some repository (semi-psuedo):
public interface IRepository
{
create();read();update();delete();opendb();closedb();
}
public class CarRepository : IRepository
{
private DbContext namedDbContext;
public void opendb()
{
namedDbContext = new DbContext();
}
public void closedb()
{
namedDbContext.dispose();
}
}
And then in a controller the repository is injected and used as follows to manually control the db connection lifetime:
public class SomeController : Controller
{
private IRepository CarRepository;
public void SomeController(IRepository _carRepository)
{
CarRepository = _carRepository;
}
public ActionResult SomeAction(int CarId)
{
CarRepository.opendb();
var car = CarRepository.read(CarId);
CarRepository.closedb();
}
}
Is this considered bad practice because it is taking the control of the connection from the repository and placing it in the controller? I am worried about memory leaks from using dependency injection and want to ensure duplicate connections are not opened, nor long running and unused.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的。当然。大多数 ADO.NET 驱动程序都使用连接池,因此实际的连接过程并不那么繁重。而且您有
TransactionScope
,它可以处理多个连接上的事务,但它不会像一个连接上的一个事务那么快。IoC 将保证清理连接(大量用户群已确保这一点)。不能保证程序员会在所有地方进行清理。
Yes. Sure. Most ADO.NET drivers uses connection pooling, so the actual connection process isn't that heavy. And you have
TransactionScope
which can take care of transaction over multiple connections, but it wont be as fast as one transaction over one connection.A IoC will guaranteed clean up the connection (a large user base have made sure of that). There is no guarantee that a programmer will do the cleanup in all places.
REpository 模式提供了持久层的抽象。它不应公开任何持久性详细信息,例如数据库连接。如果存储是xml文件或者云存储怎么办?
所以,是的,这是不好的做法。如果您想要更多控制,您可以使存储库使用工作单元模式,以便更高级别应该决定何时提交事务,但仅此而已。存储库不应公开数据库的任何知识。
对于内存泄漏,使存储库实现 IDIsposable(在其中关闭任何未完成的打开的连接),并确保 DI 容器管理每个请求的存储库实例,它将对其调用 Dispose。
The REpository pattern provides an abstraction of the persistence layer. It shouldn't expose any of the persistence details such as db connection. What if the storage is an xml file, or a cloud storage?
So yes, it is bad practice. If you want more control, you might make the repository use the unit of work pattern, so that a higher level should decide when a transaction is commited, but that's it. No knowledge of the database should be exposed by the repository.
AS for memory leaks, make repository implmement IDIsposable (where you close any outstanding open conenctions)and just makes sure that the DI container manages a repository instance per request, it will call Dispose on it.
存储库的一部分是抽象持久性的细节。
我发现您的提案有两个问题:
IDisposable
(连接对象) 来自opendb()
方法,并将操作包装在using
块中以确保连接关闭。通常,您可以让存储库为每个方法创建一个连接,因此您只需在存储库方法中正确设置它即可。当您想要对存储库执行多个操作而不为每个部分使用单独的连接时,挑战就来了。
为了实现这一点,您可以从存储库中公开工作单元的概念。您的工作单元将实现存储库方法的接口,因此您无法在工作单元之外调用它们。它还将实现
IDisposable
,因此每当您调用存储库时,您都将使用using
块。在内部,存储库将管理连接,但既不会公开连接,也不会“谈论它”。例如:
Part of a repository is abstracting away the details of persistence.
I see two problems with your proposal:
IDisposable
(the connection object) from theopendb()
method, and wrap the action in ausing
block to ensure that the connection gets closed.Typically, you can just let the repository create a connection for each method, so you just have to get it right in your repository methods. The challenge comes when you want to perform multiple actions against the repository, without using a separate connection for each piece.
To achieve that, you could expose the notion of a unit-of-work from the repository. Your unit of work will implement the interface for the repository's methods, so you can't call them outside of a unit-of-work. It will also implement
IDisposable
, so whenever you call into your repository you will use ausing
block. Internally, the repository will manage the connection, but will neither expose the connection nor "talk about it."For example: