2010-05-24 144 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