LINQ к SQL: Проблема с параллелизмом

Я работаю над тестовым приложением упорядочивания в ASP.NET MVC, C# и LINQ к SQL. Приложение вращается вокруг пользователя, создающего несколько изготовленных на заказ тестовых систем из выбора компонентов.

Когда дело доходит до подтверждения порядка я должен знать, что существует достаточно частей каждого компонента для выполнения всех тестовых систем в порядке пользователя, прежде чем я соглашусь на DB, поскольку возможно, что компонент пойдет отсутствующий на складе между добавлением его к их корзине и подтверждением порядка.

Немного о базе данных:

Компонент – детали компонента Хранилищ включая количество частей
Порядок – таблица Header для порядка, просто хранит время порядка
OrderDetail – Хранит запись каждой тестовой системы в порядке
OrderDetailItem – Хранилища каждый компонент в каждой тестовой системе в порядке

Так в основном я задаюсь вопросом, что лучший подход к обеспечению, что, прежде чем я добавлю записи на Порядок, OrderDetail и OrderDetailItem, я могу удостовериться, что порядок может быть встречен.

5
задан Gib 24 May 2010 в 11:02
поделиться

4 ответа

    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();
    }
2
ответ дан 15 December 2019 в 06:18
поделиться

Вы должны обновлять количество Ingredient каждый раз, когда вы хранить бутерброд.

Однако это не позволит другим пользователям использовать тот же ингредиент до того, как вы зафиксируете свои изменения (даже если запаса достаточно).

Лучше использовать промежуточную таблицу, которая фиксируется после добавления каждого ингредиента. Это сделает изменения сразу видимыми.

Когда вы готовы отправить заказ в целом, записи просто перемещаются из промежуточной таблицы в постоянную.

Однако вам следует реализовать некий механизм ROLLBACK для работы с устаревшими записями. Например, задание cron, которое будет отслеживать активность заказов и удалять те, которые не были активны в течение 10 минут или около того.

0
ответ дан 15 December 2019 в 06:18
поделиться

Код БД хорошо знать, но не стоит привязываться к БД, если это возможно. Отображение меню должно быть основано на текущих ингредиентах на момент просмотра, поэтому отсутствие ингредиентов должно быть редким исключением, иначе ваш магазин сэндвичей не просуществует достаточно долго, чтобы заботиться о качестве программного обеспечения.

Как избежать обхода при обновлении ингредиентов? Поддерживает ли link какую-то пакетную вставку в таблицу ингредиентов? cifey

0
ответ дан 15 December 2019 в 06:18
поделиться

Здесь можно использовать несколько подходов, но я бы сделал что-то вроде следующего псевдокода. Безопасное предположение, что обычно ингредиентов будет достаточно для удовлетворения заказа, поэтому структурируйте управление транзакциями в соответствии с этим предположением, а с редкими исключениями разбирайтесь сами.

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

Edit: Если вас удастся убедить отойти от LINQing, альтернативным подходом, позволяющим избежать обхода, будет что-то вроде следующего:

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
1
ответ дан 15 December 2019 в 06:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: