2010-05-24 86 views
5

我正在研究ASP.NET MVC,C#和LINQ to SQL中的三明治預定應用程序。該應用程序圍繞用戶創建多個定製三明治從一系列配料中挑選。LINQ to SQL:併發問題

當涉及到確認訂單時,我需要知道每個配料中有足夠的部分滿足用戶訂單中的所有三明治,然後再提交給數據庫,因爲可能會導致配料缺貨將其添加到他們的籃子並確認訂單。

有關數據庫的位:

成分 - 商店成分的細節,包括部分的數目
訂單 - 爲一個訂單Header表,簡單地存儲順序時間
的OrderDetail - 存儲一個記錄每個三明治的順序
OrderDetailItem - 按順序在每個三明治中存儲每種成分

所以基本上我想知道什麼是最好的方法來確保在向Order,OrderDetail和OrderDetailItem添加記錄之前,我可以確保能夠滿足訂單。

+0

你有一個固有的競爭條件,任何解決方案都是關於不同方法給你的可能的權衡。 – Richard 2010-05-24 11:15:19

回答

2
try 
    { 
     Begin netTransaction(); 
     If (IsEnoughIngredients()) 
     { 
      1. Build your sandwich 
      2. Add sandwich to data context with a timestamp (or whatever you chose for concurrency checking) 
      3. SubmitChangesToDataContext() 
      4. CommitNetTransaction() 
     } 
    } catch (Exception e) 
    { 
     Rollback netTransaction(); 
     InformUser(); 
    } 
+1

或使用TransactionScope – RobS 2010-05-24 11:13:57

+0

vikp - 如何在第2步中實現併發控制? – Gib 2010-05-24 14:12:23

+0

此外,我建議小心選擇事務隔離級別。 – RobS 2010-05-25 02:42:43

0

每次存儲三明治時,您應該更新Ingredient數量。

但是,這會阻止其他用戶在提交更改之前使用相同的成分(即使股價足夠)。

最好使用一個臨時表,在添加每種成分後提交。這會使更改一次顯示。

當您準備好將整個訂單提交時,記錄將從暫存錶轉移到永久記錄表中。

但是,您應該自己實施一些ROLLBACK機制來處理陳舊的記錄。例如,一個cron作業將監視訂單上的活動,並刪除那些在10分鐘左右沒有活動的作業。

1

您可以在這裏採取的方法數量,但我會做類似下面的僞代碼。安全的假設通常會有足夠的要素來滿足訂單,因此圍繞該假設構建交易控制並處理罕見的例外情況。

Begin transaction (Isolation = Repeatable Read) 

For Each OrderDetail In Order.OrderDetailCollection 
    For Each OrderDetailItem In OrderDetail.OrderDetailItemCollection 
     Update Ingredient 
     Set Portions = (Portions – OrderDetailItem.Portions) 
     Where Ingredient.ID = OrderDetailItem.IngredientID 
     And (Portions – OrderDetailItems.Portions) >= 0 

     If RecordsAffected != 1 Then 
      Rollback Transaction 
      SufficientStock = false 
      Exit For 
     End If 
    Next 

    If(SufficientStock = false) 
     Exit For 
    End If 
Next 

編輯:如果你可以說服從臨清一切一步之遙,另一種方法避免了往返程投資將沿着以下線的東西:在更新庫存水平

Begin transaction 
    Insert Order (return OrderID) 
    Insert OrderDetails 
    Insert OrderDetailItems 

    Execute update stock stored procedure (see below) 
    If (Success) 
     Commit transaction 
    Else 
     Rollback transaction 
    End IF 

代碼程序:

CREATE PROCEDURE dbo.StockLevel_UpdateByOrderID 
(
    @OrderID INT 
    , @Success BIT 
) 

SET NOCOUNT ON 
SET TRANSACTION ISOLATION LEVEL REPEATEABLE READ 

BEGIN TRANSACTION 

DECLARE @IngredientCount INT 

-- Determine number of ingredients in whole order 
SELECT 
    @IngredientCount = COUNT(odi.IngredientID) 
FROM 
    dbo.OrderDetailItem odi 
INNER JOIN 
    dbo.OrderDetail od 
ON od.OrderDetailID = odi.OrderDetailID 
WHERE 
    od.OrderID = 1 
GROUP BY 
    odi.IngredientID  

-- Update stock levels for all ingredients 
UPDATE 
    dbo.Ingredient 
SET 
    Portions = (i.Portions - odi.TotalPortions) 
FROM 
    dbo.Ingredient i 
INNER JOIN 
    (
    SELECT 
     odi.IngredientID 
     , SUM(odi.Portions) AS TotalPortions 
    FROM 
     dbo.OrderDetailItem odi 
    INNER JOIN 
     dbo.OrderDetail od 
    ON od.OrderDetailID = odi.OrderDetailID 
    WHERE 
     od.OrderID = 1 
    GROUP BY 
     odi.IngredientID 
    ) odi 
ON odi.IngredientID = i.IngredientID 
WHERE 
    (i.Portions - odi.TotalPortions) >= 0 

-- Is number of ingredients updated correct? 
IF(@@ROWCOUNT != @IngredientCount) 
BEGIN 
    ROLLBACK TRANSACTION 
    SET @Success = 0 
END 
ELSE 
BEGIN 
    COMMIT TRANSACTION 
    SET @Success = 0 
END 
0

DB代碼是很好的知道,但不好綁在一個數據庫,如果你可以幫助它。 菜單顯示應該基於當時的成分查看, 因此,如果不成份,應該是一個罕見的例外,或者您的三明治店不會長期維持軟件的良好狀態。

如何避免成分更新的往返旅程? 鏈接支持配料表上的某種批量插入嗎? cifey