简体   繁体   English

处理多个抽象存储库时的有效数据库访问

[英]Efficient database access when dealing with multiple abstracted repositories

I want to know how most people are dealing with the repository pattern when it involves hitting the same database multiple times (sometimes transactionally) and trying to do so efficiently while maintaining database agnosticism and using multiple repositories together. 我想知道大多数人如何处理存储库模式,这涉及到多次(有时是事务性地)访问同一数据库,并在保持数据库不可知性和同时使用多个存储库的情况下尝试有效地做到这一点。

Let's say we have repositories for three different entities; 假设我们有三个不同实体的存储库; Widget , Thing and Whatsit . WidgetThingWhatsit Each repository is abstracted via a base interface as per normal decoupling design processes. 每个存储库都按照常规的去耦设计过程通过基本接口进行抽象。 The base interfaces would then be IWidgetRepository , IThingRepository and IWhatsitRepository . 然后,基本接口将是IWidgetRepositoryIThingRepositoryIWhatsitRepository

Now we have our business layer or equivalent (whatever you want to call it). 现在,我们有了我们的业务层或同等业务层(无论您要调用什么)。 In this layer we have classes that access the various repositories. 在这一层中,我们有访问各种存储库的类。 Often the methods in these classes need to do batch/combined operations where multiple repositories are involved. 这些类中的方法通常需要进行涉及多个存储库的批处理/组合操作。 Sometimes one method may make use of another method internally, while that method can still be called independently. 有时一个方法可以在内部使用另一种方法,而该方法仍可以独立调用。 What about, in this scenario, when the operation needs to be transactional? 在这种情况下,当操作需要进行事务处理时该怎么办?

Example: 例:

class Bob
{
    private IWidgetRepository _widgetRepo;
    private IThingRepository _thingRepo;
    private IWhatsitRepository _whatsitRepo;

    public Bob(IWidgetRepository widgetRepo, IThingRepository thingRepo, IWhatsitRepository whatsitRepo)
    {
        _widgetRepo = widgetRepo;
        _thingRepo= thingRepo;
        _whatsitRepo= whatsitRepo;
    }

    public void DoStuff()
    {
        _widgetRepo.StoreSomeStuff();
        _thingRepo.ReadSomeStuff();
        _whatsitRepo.SaveSomething();
    }

    public void DoOtherThing()
    {
        _widgetRepo.UpdateSomething();
        DoStuff();
    }
}

How do I keep my access to that database efficient and not have a constant stream of open-close-open-close on connections and inadvertent invocation of MSDTS and whatnot? 如何保持对数据库的访问效率,并且在连接时无休止的Open-Close-Open-Close流以及对MSDTS的无意调用等? If my database is something like SQLite, standard mechanisms like creating nested transactions are going to inherently fail, yet the business layer should not have to be concerning itself with such things. 如果我的数据库是类似SQLite的数据库,则诸如创建嵌套事务之类的标准机制将固有地失败,但是业务层不必考虑此类问题。

How do you handle such issues? 您如何处理此类问题? Does ADO.Net provide simple mechanisms to handle this or do most people end up wrapping their own custom bits of code around ADO.Net to solve these types of problems? ADO.Net是提供简单的机制来解决此问题还是大多数人最终将自己的自定义代码包装在ADO.Net周围来解决这些类型的问题?

Basically you want to utilize a UnitOfWork for this. 基本上,您想为此使用UnitOfWork I personally use NHibernat e because their ISession interface is basically a Unit of Work, so it will batch together all commands and send them to the database together (there are additional smarts and object state tracking in there as well, which help with this). 我个人使用NHibernat e,因为它们的ISession接口基本上是一个工作单元,因此它将批处理所有命令并将它们一起发送到数据库(那里也有其他智能和对象状态跟踪,这将对此有所帮助)。 So the number of discrete commands sent to the database will depend on the life cycle of your ISession. 因此,发送到数据库的离散命令的数量将取决于ISession的生命周期。 In a web context I generally go with a Conversation Per Request , which means the ISession is created at the beginning of the request, and flushed (sent to the DB) at the end of the request. 在Web上下文中,我通常会使用“每个请求会话数” ,这意味着ISession是在请求开始时创建的,并在请求结束时被刷新(发送到DB)。

There is a lot of potential here to change the life cycle of the session based on whether or not you need shorter or longer session, and you can also utilize transactions which can have a separate life cycle if you need to. 根据您是否需要更短或更长的会话,此处有很大的潜力来更改会话的生命周期,如果需要,您还可以使用可以具有单独生命周期的事务。

Consider that your abstracted repositories could be implemented in any number of databases: SQLite, Microsoft SQL Server, direct file access, etc -- even though you know that they are from the same database, it's not reasonable for "Bob" to attempt to make sure each repository can be transactionalized with respect to the other repositories. 考虑一下您的抽象存储库可以在任何数量的数据库中实现:SQLite,Microsoft SQL Server,直接文件访问等-即使知道它们来自同一数据库, “ Bob”尝试创建也不合理确保每个存储库都可以相对于其他存储库进行事务处理。

Bob should perhaps talk to a DoStuffService that contains concrete implementations of your repositories. Bob也许应该与包含您的存储库的具体实现的DoStuffService进行对话。 Since this service is creating concrete implementations of your repositories, it is capable of creating an appropriate transaction. 由于此服务正在创建存储库的具体实现,因此它能够创建适当的事务。 This service would then be responsible for safely executing a UnitOfWork (thanks, ckramer ) on behalf of Bob. 然后,该服务将负责代表Bob安全地执行UnitOfWork(感谢ckramer )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM