我不确定如何结合ORM最佳地实现主详细视图。
该应用程序将WPF与MVVM一起使用,并显示所有可用对象的网格以及当前所选对象的详细信息。
视图的ViewModel非常简单,它具有:
一个ObservableCollection<ItemViewModel> Items
,其中ItemViewModel
是应在视图中显示的域对象的ViewModel。此属性绑定到网格。
绑定到网格的ItemViewModel CurrentItem
的SelectedItem
属性。ICommand
表示“添加新项目”,“删除所选项目”和“将更改保存到所选项目”。
我的应用程序使用NHibernate作为其ORM工具,但是我不想在整个代码库中泄漏NHibernate,因此我使用“工作单元”和“存储库”模式对其进行了抽象。
这些模式的NHibernate特定实现是这样的:“工作单元”在开始时打开一个新的NHibernate会话和事务,并在最后提交该事务并处置该会话。因此,工作单元,会话和事务的生命周期是相同的。工作单元具有属性Repository
,该属性使用与工作单元相同的会话,并且具有相同的生存期。
这就是问题所在:
我想在Items
的构造函数中填充MasterDetailViewModel
集合。当前,我需要创建一个新的工作单元并填充集合。为了避免长时间运行的事务,UoW将在之后直接进行处置,同时也处置基础会话。
现在,当用户要保存对当前项目的更改时,我需要打开另一个UoW,从数据库中检索实体,使用ItemViewModel
的当前值对其进行更新,将其保存到数据库中并处置该UoW 。
但是,此方法有一些重要的缺点:
我的代码里堆满了using(var uow = uowFactory.StartNew())
。
没有乐观的锁定发生。如果其他人将更改数据库中的同一项目,则其更改将被无提示地覆盖。
它需要两个数据库命中来更新项目,而不是一个。
这使我得出结论,即我的UoW的实施存在缺陷。
我考虑过更改实现,以使UoW和存储库之间的关系颠倒。这意味着IoC会将存储库而不是UnitOfWorkFactory注入到ViewModel中。现在,存储库在功能上等同于NHibernate的ISession
。存储库可以启动一个新的UoW,它现在与数据库事务相同。
这与我的“主/明细”方案配合得很好,但是它不支持通常用作“工作单位”同义词的“业务交易”概念。跨多个数据库事务和用户请求的逻辑事务。
问题是:如何最好地实现工作单元和存储库这两种模式以在两种情况下均可使用?
最佳答案
更改开始业务交易的地点并不一定会更改其粒度。
不确定我是否完全理解了您的示例,但是我看不到在每个Repository方法中(每次查询持久性存储)启动新的UoW与在MasterDetailViewModel填充时启动新的UoW粒度上有很大不同它的项目,并且每次保存其中一项时都会保存另一项。
但是,正如您所建议的那样,因为UoW具有Repository属性似乎很奇怪-UoW不会直接操作Repository,所以它是在ViewModel本身中注入Repository的,它是某个对象,它在以下环境中使用Repository哇
除此之外,我认为您几乎已经确定了短期,细粒度的业务交易所带来的弊端。您对此无能为力。
但是,还有许多其他会话策略。您可以在此article中找到一些建议。
另见
What is your session management strategy for NHibernate in desktop applications?
What should be the lifetime of an NHibernate session?