Я работаю над тестовым приложением упорядочивания в ASP.NET MVC, C# и LINQ к SQL. Приложение вращается вокруг пользователя, создающего несколько изготовленных на заказ тестовых систем из выбора компонентов.
Когда дело доходит до подтверждения порядка я должен знать, что существует достаточно частей каждого компонента для выполнения всех тестовых систем в порядке пользователя, прежде чем я соглашусь на DB, поскольку возможно, что компонент пойдет отсутствующий на складе между добавлением его к их корзине и подтверждением порядка.
Немного о базе данных:
Компонент – детали компонента Хранилищ включая количество частей
Порядок – таблица Header для порядка, просто хранит время порядка
OrderDetail – Хранит запись каждой тестовой системы в порядке
OrderDetailItem – Хранилища каждый компонент в каждой тестовой системе в порядке
Так в основном я задаюсь вопросом, что лучший подход к обеспечению, что, прежде чем я добавлю записи на Порядок, OrderDetail и OrderDetailItem, я могу удостовериться, что порядок может быть встречен.
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();
}
Вы должны обновлять количество Ingredient
каждый раз, когда вы хранить бутерброд.
Однако это не позволит другим пользователям использовать тот же ингредиент до того, как вы зафиксируете свои изменения (даже если запаса достаточно).
Лучше использовать промежуточную таблицу, которая фиксируется после добавления каждого ингредиента. Это сделает изменения сразу видимыми.
Когда вы готовы отправить заказ в целом, записи просто перемещаются из промежуточной таблицы в постоянную.
Однако вам следует реализовать некий механизм ROLLBACK
для работы с устаревшими записями. Например, задание cron, которое будет отслеживать активность заказов и удалять те, которые не были активны в течение 10
минут или около того.
Код БД хорошо знать, но не стоит привязываться к БД, если это возможно. Отображение меню должно быть основано на текущих ингредиентах на момент просмотра, поэтому отсутствие ингредиентов должно быть редким исключением, иначе ваш магазин сэндвичей не просуществует достаточно долго, чтобы заботиться о качестве программного обеспечения.
Как избежать обхода при обновлении ингредиентов? Поддерживает ли link какую-то пакетную вставку в таблицу ингредиентов? cifey
Здесь можно использовать несколько подходов, но я бы сделал что-то вроде следующего псевдокода. Безопасное предположение, что обычно ингредиентов будет достаточно для удовлетворения заказа, поэтому структурируйте управление транзакциями в соответствии с этим предположением, а с редкими исключениями разбирайтесь сами.
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