具有多个数据源的工作单元?

发布于 2024-09-17 05:56:31 字数 924 浏览 5 评论 0原文

有可能(甚至很可能)我只是没有完全理解“工作单元”的概念。基本上,我将其视为面向对象环境中使用的广泛事务。启动工作单元、与对象交互、提交或回滚。但这如何分解为这些对象背后的数据存储上的实际事务呢?

在具有单个 DB 和 ORM(例如 NHibernate)的系统中,这很容易。事务可以通过ORM来维护。但是,如果系统中的自定义域模型掩盖了许多不同的数据源,情况又如何呢?并非所有这些数据源都是关系数据库? (这里在文件系统上做了很多工作。)

现在我坚持这样一个想法:“你根本无法跨 SQL2005 DB、SQL2000 DB、DB2 DB 和文件系统维护事务”在相同的‘原子’业务运营中。”因此,目前团队中的开发人员(通常彼此独立工作)有责任在代码中手动维护事务。每个数据库都可以有适当的事务,但整个业务运营是手动检查和平衡每一个重要步骤的。

然而,随着领域复杂性的增加和标准开发人员的流动,随着时间的推移,这种方法将变得越来越困难并且容易出错。

有没有人有关于如何最好地解决这样的域的建议或示例,或者以前如何解决它?在这种情况下,实际的“域”仍然处于起步阶段,作为一个原型不断发展,有一天会扩展和消耗/替换由不同的遗留应用程序组成的大型生态系统。因此,有足够的空间进行重新设计和重构。

作为参考,我当前目标的设计的 10,000 英尺视图是:调用基于消息的中央服务的尽可能小的小型客户端应用程序的大集合。该服务是进入“域核心”的入口,可以被视为一个大型 MVC 风格的应用程序。向服务发出请求(很像“操作”),这些请求由处理程序(很像“控制器”)接收。任何程序性的东西都在那里。它们与包含所有业务规则的模型进行交互。模型发布事件,侦听器(“服务”?这部分在设计中仍然很模糊,有待改进)通过与存储库(数据库 x、数据库 y、文件系统、电子邮件、任何外部资源)交互来拾取和处理。一切都相应地愉快地进行了依赖注入。

抱歉啰嗦了:)但是如果有人有任何建议,我很乐意听到。即使(特别是)如果该建议是“你的设计很糟糕,请尝试这个......”谢谢!

It's possible (even probable) that I'm just not fully grokking the concept of a "unit of work." Basically, I see it as sort of a broad transaction used in an object-oriented environment. Start the unit of work, interact with the objects, commit or roll back. But how does this break down to the actual transactions on the data stores behind those objects?

In a system with a single DB and an ORM (such as NHibernate) it's easy. The transaction can be maintained through the ORM. But what about a system where the custom domain models are obscuring many disparate data sources? And not all of those data sources are relational databases? (There's a lot done on the file system around here.)

Right now I'm stuck on the idea that "you simply can't maintain a transaction across a SQL2005 DB, a SQL2000 DB, a DB2 DB, and the file system all in the same 'atomic' business operation." So for now it's the responsibility of the developers on the team (who generally work independently of each other) to maintain transactions manually in the code. Each DB can have proper transactions on it, but the business operation as a whole is manually checked and balanced every significant step of the way.

However, with increasing complexity in the domain and standard developer turnover, this approach will become increasingly difficult and error-prone over time.

Does anybody have any advice or examples of how a domain like this might best be addressed, or how it has been addressed before? The actual "domain" in this case is still very much in its infancy, evolving as a prototype to one day expand and consume/replace a large ecosystem of disparate legacy applications. So there's plenty of room for re-designing and re-factoring.

For reference, a 10,000-foot view of the design I'm currently aiming for is: A large collection of small as-dumb-as-possible client applications calling a central message-based service. The service is the entryway into the "domain core" and can be thought of as one big MVC-style application. Requests are made to the service (much like "actions") which are picked up by handlers (much like "controllers"). Anything procedural goes there. They interact with the models, which contain all the business rules. The models publish events which listeners ("services"? this part is still cloudy in the design and subject to improvement) pick up and handle by interacting with repositories (database x, database y, file system, email, any external resource). All merrily dependency-injected accordingly.

Sorry for all the verbosity :) But if anybody has any advice, I'd love to hear it. Even (especially) if that advice is "your design is bad, try this instead..." Thanks!

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

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

发布评论

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

评论(1

睡美人的小仙女 2024-09-24 05:56:31

我之前开发过一个可以完成此任务的系统,而且相当简单。由于您的项目还处于早期阶段,也许这对您来说可能是有用的信息。不幸的是,我无法再访问该代码,但仍然可以轻松地描述它的工作原理。

我所做的是使用通用存储库模式实现来构建我的存储库。基本存储库类型始终由服务和 UoW 引用。为了便于讨论,我们将其称为 BaseRepository。 “T”仅限于 IEntity 实现,它表示域对象。从 BaseRepository 中,我创建了另一组用于合成的基类,例如 SqlBaseRepository、XmlBaseRepository 等。

UoW 只关心 BaseRepository 类型的内容,这是核心功能所在的位置。将表示基本 CUD(CRUD),提供创建、更新和删除的等效项。其中每一个要做的就是创建一个委托并将其放置在 UoW 内的队列中,同时传递有关它将是什么类型的事务的信息以及完成它所需的适当数据。华盛顿大学将开始维护交易中需要涉及的存储库的列表,但仍然不关心它是什么类型。实际上,在这里排队就像参加交易一样。

BaseRepository 定义了一个名为 .ApplyChange() 的抽象方法。一旦在UoW上调用.Commit(),它将创建一个TransactionScope()并开始调用列表中的委托,将信息传回.ApplyChange()。 .ApplyChange() 的实际实现存在于特定的存储库库中,即 SqlRepositoryBase 等,并且也可以被实现覆盖。

至少对我来说,棘手的地方是回滚。我只处理单个数据库,但有时会进行基于文件的更改。我添加了 .RevertChange() 方法并开始跟踪原始状态和修改后的状态,以便我基本上可以应用反向增量来返回到文件堆栈上的位置。

我希望我能更具体地说明实现,但自从我看到代码以来已经一年多了。我可以告诉你,原始代码的基础来自这本书,.NET Domain-使用 C# 驱动设计:问题 - 设计 - 解决方案,作者:Tim McCarthy。我的大量存储库实现都是基于他的示例,我的大部分定制都来自 UoW 及其实现。

我希望这有所帮助! :-)

I previously worked on a system that could accomplish this, and it is fairly straightforward. Since you project is in its early stages, perhaps this could be useful information for you. Unfortunately, I no longer have access to the code, but am still comfortable in describing how it worked.

What I had done was built my repositories using a generic repository pattern implementation. The base repository type would always be references by the services and UoW. For sake of discussion, we will call it BaseRepository. "T" would be restricted to IEntity implementations, which denoted a Domain Object. From the BaseRepository, I had created another set of base classes for compositing, such as SqlBaseRepository, XmlBaseRepository, etc.

The UoW only cares that something is of the type BaseRepository, which is where the core functionality would exist. Basic CUD (of CRUD) would be represented, providing the equivalents for Creates, Updates, and Deletes. What each of these would do would be to create a delegate and place it in a queue inside the UoW, also passing along information about what type of transaction it was going to be, and the appropriate data required to complete it. The UoW would start maintaining a list of what repositories were going to need to be involved in the transaction, but still did not care what type it was. Effictively, queueing up here is like enlisting in a transaction.

The BaseRepository defined an abstract method called something like .ApplyChange(). Once .Commit() was called on the UoW, it would create a TransactionScope() and start calling the delagates in the list, passing back the information to .ApplyChange(). The actual implementation of .ApplyChange() exists in the specific repository base, i.e. the SqlRepositoryBase, etc. and could be overridden by the implementation, as well.

Where it got tricky, for me at least, was rolling back. I only dealt with a single database, but sometimes had file-based changes that were made. I added a .RevertChange() method and started tracking the original state and modified states so that I could basically apply a reverse-delta to get back to where I was on the file stack.

I wish that I could be more specific on the implementation, but it has been over a year since I have seen the code now. I can tell you that the basis for the original code was borne from the book, .NET Domain-Driven Design with C#: Problem - Design - Solution, by Tim McCarthy. A large amount of my repository implementation was based on his examples, with a large majority of my customization coming in on the UoWs and their implementation.

I hope that helps, somewhat! :-)

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