我使用 nhibernate 作为我的 orm,我正在尝试实现一些看起来简单但变得不必要的困难的东西。它涉及如何实现对实体的并发更新,在多用户场景中,预计该实体将由多个用户同时更新。该实体是具有余额的某种帐户。
一个例子是一个库存系统,它需要根据进出的移动条目来更新库存项目的余额。我在下面包含了以下代码的缩短版本。该代码只是保存条目并依赖 nhibernate 级联保存到项目。
该系统预计可以处理多个用户。这些对象是在一段时间内在 UI 中创建的。每个项目的余额将根据在 UI 中创建条目和获取项目时的手头数量进行调整。用户最终保存可能需要几分钟时间。
如果另一个用户对相同的项目进行了其他输入,则第一个用户正在使用的余额现在无效。我知道如果尝试保存,NHibernate 会抛出一个过时的数据异常。但这不是我想要的,因为并发更新是必需的。我想要的是该项目的当前余额根据条目数量的需要增加或减少。或者在更新时再次获取该项目,锁定,执行重新计算然后最终更新,但我不知道在这种情况下如何实现这一点以及代码的确切位置。我想避免它在域对象中,因为控制悲观锁定等是应用程序/持久性问题。看起来这应该是一个常见的场景,但我还没有看到任何讨论这个的东西。
PS 我有另一个担心我上面概述的 refetch-lock-recalculate-update 方法在条目有很多行的情况下如何。是否会为每个项目发送单独的锁定请求,或者是否有办法一次性获取入口行的所有项目的锁定。
任何帮助,将不胜感激。
class TestConcurrentUpdates
{
ISession session;
Entry entry;
ItemRepository itemRep;
EntryRepository entryRep;
void testMethod()
{
...
Entry entry = new Entry();
Item item1 = itemRepository.Get(item1ID);
Item item2 = itemRepository.Get(item1ID);
Item item3 = itemRepository.Get(item1ID);
entry.Lines.Add(new EntryLine(this, item1, 10));
entry.Lines.Add(new EntryLine(this, item2, -4));
entry.Lines.Add(new EntryLine(this, item3, 2));
using (ITransaction transaction = session.BeginTransaction())
{
entryRep.Save(entry);
transaction.Commit();
}
}
}
Item
{
string name;
double balance;
IList<EntryLine> entries = new List<EntryLine>();
public double getBalance() { return balance; }
void addEntryLine(EntryLine line)
{
entries.add(line);
balance += line.getQuantity();
}
}
class Entry
{
IList<EntryLine> lines = new List<EntryLine>();
public IList<EntryLine> Lines { get { return lines; } }
}
class EntryLine
{
Entry entry;
double quantity;
Item item;
public EntryLine(Entry entry, Item item, double quantity)
{
this.entry = entry;
this.quantity = quantity;
this.item = item;
item.addEntryLine(this);
}
public double getQuantity()
{
return quantity;
}
}