存储库是单例还是静态还是都不是?

发布于 2024-12-05 08:22:45 字数 126 浏览 6 评论 0原文

我有一个 ASP.NET 网站,它使用域驱动设计并使用存储库进行数据库操作。
我想知道单例存储库和静态存储库以及每次访问都会新增的简单存储库类的优缺点是什么?
此外,如果有人可以比较并指导我使用其中的哪一个,我将不胜感激。

I have a ASP.NET web site which uses domain driven design and uses repository for its database operations.
I want to know that what is pros and cons of singleton repository and static repository and simple repository class which will new on every access?
further more if anyone can compare and guide me to use which one of them I will be appreciate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凤舞天涯 2024-12-12 08:22:45

静态和单例对于存储库模式来说不是很好的解决方案。如果您的应用程序将来将使用 2 个或更多存储库怎么办?

IMO 最好的解决方案是使用依赖注入容器并将 IRepository 接口注入需要它的类中。

我建议你阅读一本关于领域驱动设计的好书和一本关于依赖注入的好书(比如 Mark Seeman 的 Dependency Injection in .NET)。


使用单例和静态类,您的应用程序将无法扩展

您有两个单例存储库:

class Repository<TEntity> {

  static Repository<TEntity> Instance { get { ... /*using sql server*/ } }
}

class Repository2<TEntity> {

  static Repository2<TEntity> Instance { get { ... /*using WCF or XML or any else */ } }
}

使用它们的服务必须对其中之一或两者都有静态引用:

class OrderService {

    public void Save(Order order) { Repository<Order>.Instance.Insert(order); }
}

如果存储库是,如何使用 Repository2 保存订单静态引用?

更好的解决方案是使用 DI:

interface IRepository<TEntity> { ... }

class SqlRepository<TEntity> : IRepository<TEntity> { ....}

class OrderService {
    private readonly IRepository<TEntity> _repo;

    public OrderService(IRepository<TEntity> repo) { _repo = repo; }

    public void Save(Order order) { repo.Insert(order); }
}

Static and singleton aren't good solution for Repository pattern. What if your application will use 2 or more repositories in the future?

IMO the best solution is to use a Dependency Injection container and inject your IRepository interface in the classes that need it.

I suggest you to read a good book about domain driven design and a good book about dependency injection (like Mark Seeman's Dependency Injection in .NET).


With singletons and static classes your application won't be scalable

You have two singleton repositories:

class Repository<TEntity> {

  static Repository<TEntity> Instance { get { ... /*using sql server*/ } }
}

class Repository2<TEntity> {

  static Repository2<TEntity> Instance { get { ... /*using WCF or XML or any else */ } }
}

The services using them must have a static reference to one of them or both:

class OrderService {

    public void Save(Order order) { Repository<Order>.Instance.Insert(order); }
}

How can you save your order using Repository2, if the repository is statically referenced?

A better solution is using DI:

interface IRepository<TEntity> { ... }

class SqlRepository<TEntity> : IRepository<TEntity> { ....}

class OrderService {
    private readonly IRepository<TEntity> _repo;

    public OrderService(IRepository<TEntity> repo) { _repo = repo; }

    public void Save(Order order) { repo.Insert(order); }
}
醉南桥 2024-12-12 08:22:45

不要使用静态或单例存储库,因为:

  • 它会影响可测试性,在单元测试时无法模拟它。

  • 它会影响可扩展性,您不能进行多个具体实现,并且在不重新编译的情况下无法替换行为。

  • 它影响生命周期管理方面的可扩展性,insetead依赖依赖注入框架来注入依赖并管理生命周期。

  • 它影响可维护性,它强制依赖于具体实现而不是抽象。

底线:不要使用静态或单例存储库

,而是在域模型项目中创建存储库接口,并在具体的数据访问项目中实现这些接口,并使用依赖项注入框架。

Don't use static or singleton repositories because of:

  • It affects testablility, you can not mock it when unit testing.

  • It affects extensibility, you can not make more than one concrete implementation and you can not replace behavior without re-compiling.

  • It affects scalability in terms of lifecycle management, insetead depend on dependency injection framework to inject the dependency and manage lifecycle.

  • It affects maintainability, it forces dependency upon concrete implementation instead of abstraction.

Bottom line: DONT use static or singleton repositories

instead create repository interfaces in your domain model project, and implement these interfaces in a concrete data access project, and use dependency injection framework.

转角预定愛 2024-12-12 08:22:45

我个人恭敬地不同意以前的答案。

我开发了多个网站(其中一个每月有 700 万次页面浏览量),并且我的静态存储库从未出现过任何问题。

我的静态存储库实现非常简单,仅包含对象提供程序作为属性。单个存储库可以包含您需要的任意数量的提供程序。

然后,提供者负责管理数据库连接和事务。使用 TransactionScope,消费者可以管理交易或将其交给提供者。

每个提供程序都是使用单例模式开发的。

这样,我可以通过简单地调用以下方法来获取我的对象:

var myObj = MyRepository.MyProvider.GetMyObject(id);

在任何时候,我的应用程序的每个 Web 池中每种类型只有一个存储库和一个提供程序。根据您网站上同时拥有的用户数量,您可以设置多个网络池(但大多数时候一个就足够了)。

我看不到我的存储库/提供者消费者与我的存储库的耦合位置。事实上,我的提供者的实现完全是从它们中抽象出来的。当然,我的存储库返回的所有提供程序都是接口,我可以随时轻松更改它们的实现并将我的新 dll 推送到 Web 服务器上。如果我想创建一个具有相同接口的全新提供程序,我只需在一个地方更改它:我的存储库。

这样,无需添加依赖项注入或创建自己的 ControllerFactory(对于 MVC 项目)。

而且您的控制器中仍然具有干净代码的优势。每次请求页面时(通常在 ControllerFactory 中使用反射),您还将节省大量存储库创建和销毁的时间。

如果您正在寻找可扩展的解决方案(如果您确实需要它,但大多数时候这并不是真正的问题),那么与依赖项注入相比,我开发存储库的方式永远不会成为问题。

I personally respectfully disagree with previous answers.

I have developed multiple websites (one with 7 millions page views per month) and never had a single problem with my static repositories.

My static repository implementation is pretty simple and only contains objects providers as properties. A single repository can contain as many providers as you need.

Then, the providers are responsible to manage database connection and transactions. Using TransactionScope, the consumer could manage the transactions or let it to the providers.

Every providers are developed using the singleton pattern.

This way, I can get my objects by simply calling this :

var myObj = MyRepository.MyProvider.GetMyObject(id);

At any time, there is only one repository and one provider of each type in every web pool of my application. Depending on how many users you have at the same time on your site, you could set more than one web pool (but most of the time one is just enough).

I don't see where my repository/providers consumers are coupled with my repository. In fact, the implementations of my providers are totally abstracted from them. Of course, all providers returned by my repository are interfaces and I could easily change the implementation of them at any time and push my new dll on the web server. If I want to create a completely new provider with the same interface, I only have to change it in ONE place: my repository.

This way, no need to add dependency injection or having to create your own ControllerFactory (for MVC procjects).

And you still have the advantage of clean code in your controllers. You will also save a lot of repository creation and destruction every time a page is requested (which normally use reflection in your ControllerFactory).

If you are looking for a scalable solution (if you really need it which most of the time is not really a problem), my way of developing repositories should never be a problem compared to dependency injection.

蹲在坟头点根烟 2024-12-12 08:22:45

没有单例存储库的两个SOLID理由:

  • 存储库的使用者将耦合 到存储库实施。这将对可扩展性和可测试性产生负面影响。这是 DIP 违规行为。依赖于抽象,而不是具体。

  • 存储库实施必须违反SRP,因为它很可能最终会失败管理 ORM 会话、数据库连接和潜在的事务。它还必须保证线程安全,因为它可能可以从多个线程使用。相反,应该将数据库连接(ORM 会话)注入到存储库实现中,以便使用代码可以将多个存储库调用安排到事务中。

这两个问题的可能解决方案是构造函数注入

Two SOLID reasons to not have singleton repository:

  • Consumers of repository will be coupled to repository implementation. This will negatively affect extensibility and testabiliy. This is a DIP violation. Depend on abstractions, not on concretions.

  • Repository implementation will have to violate SRP because it will most likely end up managing ORM session, database connection and potentially transactions. It would also have to make thread safe guarantees because it potentially can be used from multiple threads. Instead, database connection (ORM Session) should be injected into repository implementation so that consuming code can arrange multiple repository calls into transaction.

Possible solution to both problems is Constructor Injection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文