0

Ich habe einen Endpunkt (ASP.NET WebAPI + Entity Framework 6), der das Hinzufügen von Elementen zu einem Warenkorb ermöglicht. Es sieht wie folgt aus:Basket Item mit mit TransactionScope.ReadCommitted immer noch Duplikate erstellen

public int AddToBasket(BasketUpdate update) 
    { 
     var transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; 
     using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions)) 
     { 
      var existingBasketItem = basketItems.Query().FirstOrDefault(item => 
        item.UserId == update.UserId 
        && item.AccountId == update.AccountId 
        && item.ProductId == update.ProductId); 
  existingBasketItem = existingBasketItem ?? basketItems.Create(); 
      existingBasketItem.Quantity += update.Quantity; 
      existingBasketItem.AccountId = update.AccountId; 
      existingBasketItem.UserId = update.UserId; 
      existingBasketItem.ProductId = update.ProductId; 

      unitOfWork.Commit(); 

      scope.Complete(); 

      return existingBasketItem.Quantity; 
     } 
    } 

So nahm ich (in meiner endlosen Krippe), wenn ich mehrere Anrufe auf diesen Endpunkt Feuer, ich mit einem Eintrag immer am Ende in der Datenbank Aufsummierung die Mengen aller Anrufe korrekt. Das Durchdringen dieses Endpunkts mit Fiddler scheint zu bestätigen, dass alle Anforderungen warten, bis der vorherige abgeschlossen ist.

aber sobald ich aufhören, (oder jemand anderer Artikel fügt den Korb), ich am Ende so etwas mit:

Id Quantity ProductId UserId AccountId 
429 12  4560   56 2234 
430 1  4560   56 2234 

Wie auf der Erde vorkommen, dass kann? Gibt es zufällig irgendwann zwei Instanzen auf dem IIS-Server oder missverstehe ich etwas über Transaktionen hier? Zieht mir schon die Haare, so würde Hilfe sehr geschätzt werden.

Antwort

0

Dieser Ansatz funktioniert überhaupt nicht. Es scheint keinen EntityFramework-Ansatz zu geben, der dies ausreichend löst. Selbst die Ebene "Serialisierbar" sperrt nur die ausgewählten Daten, was dazu führt, dass neue Zeilen eingefügt werden, die es erfordern, dass der Dienstcode die in mehrere Zeilen aufgeteilte Menge behandelt.

Also habe ich eine Stored Procedure geschrieben mit MERGE mit einem TABLOCK bietet exklusive lesen und schreiben auf den Tisch und die Geschwindigkeit.

ALTER PROCEDURE [dbo].[UpdateSalesQuantity] 
@AccountId   INT, 
@ProductId   INT, 
@Quantity   INT, 
@AddNotSetQuantity BIT 
AS 
BEGIN 
SET NOCOUNT ON; 

MERGE INTO dbo.BasketItem WITH (TABLOCK) AS target 
USING (Select @AccountId AccountId, @ProductId ProductId) AS source 
ON 
    target.AccountId = source.AccountId 
    AND target.ProductId = source.ProductId 
WHEN MATCHED AND (@AddNotSetQuantity = 0 AND @Quantity > 0) OR (@AddNotSetQuantity = 1 AND target.Quantity + @Quantity > 0) 
    THEN UPDATE SET target.Quantity = (CASE @AddNotSetQuantity WHEN 0 THEN 0 ELSE target.Quantity END) + @Quantity 
WHEN MATCHED AND (@AddNotSetQuantity = 0 AND @Quantity <= 0) OR (@AddNotSetQuantity = 1 AND target.Quantity + @Quantity <= 0) 
    THEN DELETE 
WHEN NOT MATCHED BY TARGET AND @Quantity > 0 
    THEN INSERT (ProductId, AccountId, CreationTime, ModificationTime, [Guid], Quantity) 
     VALUES (@ProductId, @AccountId, GETDATE(), GETDATE(), NEWID(), @Quantity); 

SELECT Quantity FROM dbo.BasketItem WHERE AccountId = @AccountId And ProductId = @ProductId 
END 
Verwandte Themen