数据持久层需要多少个抽象级别?
我正在使用 DDD 技术编写一个应用程序。这是我第一次尝试 DDD 项目。这也是我的第一个绿地项目,我是唯一的开发商。我已经充实了域模型和用户界面。现在我从持久层开始。像往常一样,我从单元测试开始。
[Test]
public void ShouldAddEmployerToCollection()
{
var employerRepository = new EmployerRepository();
var employer = _mockery.NewMock<Employer>();
employerRepository.Add(employer);
_mockery.VerifyAllExpectationsHaveBeenMet();
}
正如您所看到的,我没有写出对 Add() 函数的任何期望。到目前为止,我意识到我还没有选定特定的数据库供应商。事实上,我什至不确定它是否需要数据库引擎。平面文件或 xml 可能同样合理。所以我想知道我的下一步应该是什么。
我应该添加另一层抽象吗...例如 DataStore 接口还是寻找已经为我完成工作的现有库?如果可以的话,我想避免将程序与特定的数据库技术联系起来。
I'm writing an application using DDD techniques. This is my first attempt at a DDD project. It is also my first greenfield project and I am the sole developer. I've fleshed out the domain model and User interface. Now I'm starting on the persistence layer. I start with a unit test, as usual.
[Test]
public void ShouldAddEmployerToCollection()
{
var employerRepository = new EmployerRepository();
var employer = _mockery.NewMock<Employer>();
employerRepository.Add(employer);
_mockery.VerifyAllExpectationsHaveBeenMet();
}
As you can see I haven't written any expectations for the Add() function. I got this far and realized I haven't settled on a particular database vendor yet. In fact I'm not even sure it calls for a db engine at all. Flat files or xml may be just as reasonable. So I'm left wondering what my next step should be.
Should I add another layer of abstraction... say a DataStore interface or look for an existing library that's already done the work for me? I'd like to avoid tying the program to a particular database technology if I can.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
根据您的要求,您真正需要的唯一抽象是具有基本 CRUD 语义的存储库接口,以便您的客户端代码和协作对象仅处理 IEmployerRepository 对象而不是具体存储库。您有几种选择:
1)不再抽象。只需在您需要的顶级应用程序中构建具体的存储库即可:
在一百万个地方进行更改将会过时,因此该技术仅适用于非常小的项目。
2) 创建要在应用程序中使用的存储库工厂:
您可以将存储库工厂传递到将使用它的类中,或者您可以创建一个应用程序级静态变量来保存它(它是一个单例,这是不幸的,但相当有限)。
3)使用依赖注入容器(本质上是通用工厂和配置机制):
如果您以前没有使用过 DI 容器,那么这里有很多关于它们的很好的问题和答案(例如 哪些 C#/.NET 依赖注入框架值得正在调查?和数据访问、单元测试、依赖注入 ),并且您肯定想阅读 Martin Fowler 的 控制容器反转和依赖注入模式 )。
With your requirements, the only abstraction you really need is a repository interface that has basic CRUD semantics so that your client code and collaborating objects only deal with
IEmployerRepository
objects rather than concrete repositories. You have a few options for going about that:1) No more abstractions. Just construct the concrete repository in your top-level application where you need it:
Changing that in a million places will get old, so this technique is only really viable for very small projects.
2) Create repository factories to use in your application:
You might pass the repository factory into the classes that will use it, or you might create an application-level static variable to hold it (it's a singleton, which is unfortunate, but fairly well-bounded).
3) Use a dependency injection container (essentially a general-purpose factory and configuration mechanism):
If you haven't used DI containers before, there are lots of good questions and answers about them here on SO (such as Which C#/.NET Dependency Injection frameworks are worth looking into? and Data access, unit testing, dependency injection), and you would definitely want to read Martin Fowler's Inversion of Control Containers and the Dependency Injection pattern).
在某些时候,您将必须调用您的存储库将如何处理数据。当您开始项目时,最好使其尽可能简单,并且仅在必要时添加抽象层。在这个阶段,简单地定义您的存储库/DAO 可能就足够了。
通常,存储库/存储库/DAO 应该了解您决定使用哪个数据库或 ORM 的实现细节。我想这就是您在 DDD 中使用存储库的原因。这样您的测试就可以模拟存储库并且不知道实现。
At some point you will have to make a call as to what your repository will do with the data. When you're starting your project it's probably best to keep it as simple as possible, and only add abstraction layers when necessary. Simply defining what your repositories / DAOs are is probably enough at this stage.
Usually, the repository / repositories / DAOs should know about the implementation details of which database or ORM you have decided to use. I expect this is why you are using repositories in DDD. This way your tests can mock the repositories and be agnostic of the implementation.
我写了一篇关于在 NHibernate 之上实现存储库模式的博客文章,我认为无论您是否使用 NHibernate,它都会使您受益。
创建一个通用的通用和可扩展的NHiberate存储库
I wrote a blog post on implementing the Repository pattern on top of NHibernate, I think it will benefit you regardless of whether you use NHibernate or not.
Creating a common generic and extensible NHiberate Repository
我在持久层中发现的一件事是确保有一个地方可以开始进行抽象。如果数据库不断增长,您可能需要开始实施分片,除非已经有可用的抽象层,否则以后添加抽象层可能会很困难。
One thing I've found with persistence layers is to make sure that there is a spot where you can start doing abstraction. If you're database grows, you might need to start implementing sharding and unless there's already an abstraction layer already available, it can be difficult to add one later.
我相信您不应该仅仅为了单元测试的目的而在存储库类下面添加另一层,特别是如果您没有选择持久性技术。我认为您无法在不公开有关持久性方法的详细信息的情况下创建比“repository.GetEmployee(id)”更精细的接口。
如果您确实考虑使用纯文本或 XML 文件,我相信最好的选择是坚持使用存储库接口抽象。但是,如果您决定使用数据库,并且不确定供应商,那么 ORM 工具可能是您的最佳选择。
I believe you shouldn't add yet another layer below the repository classes just for the purpose of unit testing, specially if you haven't chosen your persistence technology. I don't think you can create an interface more granular than "repository.GetEmployee(id)" without exposing details about the persistence method.
If you're really considering using flat text or XML files, I believe the best option is to stick with the repository interface abstraction. But if you have decided to use databases, and you're just not sure about the vendor, an ORM tool might be the way to go.