2

我使用 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; 
   } 
}
4

0 回答 0