2012-06-25 72 views
1

我想了解實體框架是如何工作的。我知道EF SaveChanges基本上是一個事務性更新的包裝。我也明白,如果需要,你可以在TransactionScope中包裝兩個上下文。庫存系統的實體框架交易

我正在使用Code First方法。

我不明白什麼是我會怎麼做像

UPDATE Inventory SET Available = Available - 1 WHERE Available > 0 

更新換句話說 - 如何確保至少有X可用庫存做更新之前?

我想我可以編寫代碼,着眼於商品的庫存,並驗證有足夠的庫存來完成購買:

if (Product.Inventory - quantityToPurchase < 0) throw new Exception(..) 

但是,我們在方案中,其中兩個客戶試圖在買同一時間和從數據庫中爲每個客戶提取的對象聲稱在庫存中有2個項目?我上面的邏輯無法理解。

如何確保SaveChanges()方法僅提交對象IF和ONLY的更改如果(Available - quantity)大於0?

回答

1

默認實體框架使用樂觀併發。我在原來的文章中所描述的在EF中被稱爲悲觀併發(Pessimistic Concurrency)。有兩個屬性可以用來實現這一點。

首先是Timestamp它將在表中創建一個rowversion列。 EF將自動檢測到此信息,並且將始終將where子句添加到更新中,將實體的屬性值與數據庫中列的值進行比較。只有兩者匹配時,update聲明纔會成功。 rowversion列自動遞增。這可以確保您始終更新您在內存中的相同數據(在POCO中)。如果其他人在獲取該行後更改該行,則更新將失敗。

其次是ConcurrencyCheck,其工作原理類似於Timestamp。這將導致POCO資產的價值包含在where條款中。最大的區別是它不會像rowversion那樣更新此列。

+1

我很高興你知道你在做什麼,並將其發佈在這裏!我不確定這個問題是否是一個「併發」問題,但是我確實知道如何使用與併發管理相同的技術來解決它。無論哪種方式,感謝張貼這個B/C我學到了一些東西。 – kingdango

+1

它是一個併發問題,因爲我不希望兩個用戶同時更新清單行,從而允許超額清點庫存。由於EF首先從數據庫加載數據,然後將其寫回,因此兩個用戶可能同時加載數據的機會是「我們有2件襯衫庫存」,然後都嘗試寫回同一行這表明他們每人都購買了2件襯衫。這意味着我現在已經超賣了襯衫。上面的方法通過確保您寫入的行沒有被讀取後被修改,從而避免了這種情況。 –

+0

是的,這很有道理,謝謝你的描述。 – kingdango

1

你需要做這種檢查,當你通過覆蓋SaveChanges方法節省了實體:

public override int SaveChanges() 
{ 
    var entities = ChangeTracker.Entries() 
           .Where(e => e.State == EntityState.Added || 
              e.State == EntityState.Modified) 
           .Select(e => e.Entity()) 
           .OfType<YourEntityType(); 

    foreach (var entity in entities) 
    { 
     // Run business rule 
    } 

    return base.SaveChanges(); 
} 
+0

我認爲這與我在問題中提到的方法非常相似。這基本上將業務規則留給應用程序,但在數據庫級別不提供任何強制操作。雖然不太可能,但這仍然可能導致庫存過大。 –

+0

正確的是,您正在使用實體框架,因此您的數據訪問層將需要強制執行關鍵約束等以外的規則。您的規則(不要超出庫存)是一個典型的業務規則,應由應用程序處理,而不是數據庫。 – kingdango