工作单元、回滚选项
我正在尝试构建一个遵循存储库和工作单元模式的系统,以允许持久性无知/单元测试等。我正在寻找有关处理回滚的建议。理想情况下,我想使用 POCO,但我认为我可能至少需要实现一个接口来提供一些零碎的东西。
假设我们有两个存储库,一个上下文/工作单元。
我添加一项、修改另一项并删除第三项。对第二个存储库重复此操作,然后调用回滚。
过去我为此使用了类似于数据集的东西。每个对象都有一个状态:pendingNew、pendingAmished、pendingDeleted、clean。还有一个对象的最后持久版本的副本用于回滚。
你会如何实施这个?
编辑:
好的,这就是我想我实际上正在尝试解决的问题。准备好进行模式化:)
最终该项目是 WPF MVVM。所以我们正在研究这里的商店的模型。
我认为我一直在尝试将模型与存储库的概念混为一谈,因为我认为模型应该使用 UOW 和存储库来提供模型需要提供的功能。听起来更好吗?
我想要完全持久的无知,所以想象我的域包括一个客户、一个订单和订单行。
假设 GUI 有一个按钮新订单,允许用户填写客户详细信息、订单详细信息和 1-n OrderLine 详细信息。他点击“保存”,他们就会进入数据库,他点击“取消”,他们不会。
因此,在这种情况下,模型可能会向 CustomerRepository 询问客户,然后向 OrderRepository 询问新订单,然后向 OrderLineRepository 询问每个新行,然后告诉工作单元保存它们。
听起来合理吗?对我来说确实如此,我认为这就是定义分离的地方。我很想在模型和存储库之间使用另一个 API。不,那太愚蠢了。
编辑2:这是一篇优秀的文章,有一定的帮助< /a> 一点点。
I'm trying to build a system which follows the repository and unit of work patterns to allow persistence ignorance/unit testing, etc etc. I'm looking for advice on dealing with Rollback. Ideally I want to use POCO's but I think I might need to at least implement an interface to provide a few bits and pieces.
So lets say we have two repositories, one context/unit of work.
I add one item, amend another item and delete a third item. Repeat for second repository, then I call rollback.
In the past I've used something akin to a DataSet for this. Each object has a state of pendingNew, pendingAmended, pendingDeleted, clean. There is also a copy last persisted version of the object for rollback.
How would you implement this?
EDIT:
Ok, here's what I think I'm actually trying to get my head around. Prepare to be patterned :)
Ultimately the project is WPF MVVM. So we're looking at the Model to what ever the store is here.
I think I've been trying to conflate the model with the idea of repository, where as I think the model should use the UOW and Repositories to provide the features the model needs to provide. Does that sound better?
I want complete persistence ignorance, so imagine my domain includes a Customer, an Order and OrderLines.
The GUI let's say has one button new order which allows the user to fill in Customer details, Order details and 1-n OrderLine details. He hits save and they go to the database, he hits cancel they don't.
So, in this case the model might ask the CustomerRepository for a customer, then the OrderRepository for a new Order, then the OrderLineRepository for each new Line, then tell the Unit of Work to save them.
Does that sound reasonable? It does to me, I think it's where the separation is defined. I'm half tempted to have another API between the model and the repositories. No, that's silly.
EDIT 2: This is an excellent article that has sort of helped a little.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我设计的工作单元和存储库类与MSDN 上的描述类似。
IUnitOfWork
类的基本思想是它自己处理所有数据库工作。然后,我添加了一个
BeginTransaction()
方法(添加到我的IUnitOfWork
类和实现中),该方法打开一个TransactionScope()
对象,然后添加了一个EndTransaction(bool commit)
方法。此方法通过将事务提交到数据库(如果为 true)或回滚事务(如果为 false)来处理关闭事务。这使我能够控制复杂的事务,从而允许回滚多个提交。
编辑:
我的想法是你希望你的 UnitOfWork 对象了解存储库,而不是相反。这是我的观点,你会发现有人持相反的观点,但原因如下。
当您想要以某种方式处理数据库时,您希望它全部受到当前工作单元的约束。因此,对我来说,通过工作单元来访问您的存储库,而不是让您的存储库访问您的工作单元,这是合乎逻辑的。
如果您需要分支并在不同的数据库上执行多项操作(例如,如果历史数据与实时数据写入不同的数据库,或者如果您正在进行水平数据库分区),它也会变得更容易,因为每个数据库都会有它是自己的工作单位。原因是,如果您让存储库了解工作单元,则需要为每个数据库创建一个工作单元,以及可能需要访问它的每个工作单元所需的每个存储库的副本。
最后,保持对存储库的访问仅通过您的工作单元进行访问,可以使 API 对开发人员来说变得简单。对于初学者来说,您只需要实例化 1 个对象(工作单元),而不是 1 个工作单元对象加上您可能需要的多个存储库对象。它使您的代码保持简单(恕我直言),并使开发人员更不容易出错。
I designed my unit of work and repository classes similar to how it's described here on MSDN. The basic idea of the
IUnitOfWork
class is that it handles all the database work itself.I then added (to my
IUnitOfWork
class and implementations) aBeginTransaction()
method, which opens aTransactionScope()
object, and then added aEndTransaction(bool commit)
method. This method handles closing the transaction, either by committing the transaction to the database (if true) or rolling back the transaction (if false).This allows me to do control complicated transactions allowing multiple commits to be rolled back.
Edit:
My line of thinking is you want your UnitOfWork object to know about the repositories and not the other way around. This is my opinion, and you'll find people who like the opposite but here's why.
When you want to deal with the database in some way, you want it all constrained by your current unit of work. So to me it makes logical sense to go through the unit of work in order to access your repositories, rather than having your repositories access your unit of work.
It also makes it easier if you need to branch out and do multiple things on different databases (for example, if history data is written to a different database than live data, or if you are doing horizontal database partitioning), since each database would have it's own unit of work. The reason is that if you make repositories know of the unit of work, you need to create one unit of work for each database, plus copy of each repository that you need for each unit of work you may need to access it to.
Finally, keeping access to your repositories as being accessed only through your unit of work keeps the API simple for the developers. For starters, you only need to instantiate 1 object (the unit of work) instead of 1 unit of work object plus however many repository objects you may need. It keeps your code simple (imho) and makes things a bit less error prone for the developers.
如果没有更多细节,很难确定,但我会研究从 IDbConnection 接口和关联接口实现。它为您提供了大多数具有任何经验的 C# 编码人员都会熟悉的界面。
老实说,在幕后,这实际上取决于存储机制的效率。如果它有效地处理大量更改,那么您最好让回滚机制构建一个执行回滚时应采取的操作列表,该列表在“提交”时被丢弃。另一方面,如果更新成本很高,那么事务机制会维护一个在提交时执行的操作列表,这些操作在回滚时会被丢弃。您还需要考虑其他代码是否应该在提交之前看到更新;如果采用前一种方法,他们会这样做,如果采用后者,则不会。
It's difficult to say for sure without more detail, but I'd look into implementing from the
IDbConnection
interface and associated interfaces. It gives you an interface most C# coders with any experience will be familiar with.Under the hood, to be honest, it really depends on the efficiency if your storage mechanism. If it handles lots of changes efficiently, then you're probably better off having your rollback mechanism build a list of actions that it should take to do a rollback, which is discarded on a 'commit'. If on the other hand updates are expensive, then have you transaction mechanism maintain a list of actions to do on a commit, which are discarded on a rollback. You also need to think about whether or not other code should see updates prior to a commit; with the former approach they will, with the latter, they won't.
我将通过使用 NHibernate 或实体框架之类的框架来实现这一点。 :)
NHibernate 允许您使用 POCO,并且已经为您完成了所有的工作。
I would implement this by using a framework like NHibernate or Entity Framework to do this. :)
NHibernate allows you to use POCO's, and does all the plumbing for you already.