2017-09-22 25 views
0

私たちは、人々がギフトカードを購入できるeコマースのウェブサイトを持っています。これらのカードは、ロジスティック目的でテーブルに格納され、整数で順序付けされています。誰かがギフトカードを購入した場合、データベースに購入注文を挿入し、最初の適格なカードのフィールドを編集して、もう使用できなくなったことを知ります。閲覧用ロックテーブル

しかし、2人のユーザーが同じ時間にカードを購入した場合、同じカードが両方のカードに与えられることがあります。そこで私たちはIsolationLevel.ReadCommittedとの取引をしましたが、これはうまくいきません。同時クリック数が4回の場合は、2 PurchaseOrderの場合はCard、2 PurchaseOrderの場合はCardとなります。

TransactionOptions transOption = new TransactionOptions(); 
transOption.IsolationLevel = IsolationLevel.ReadCommitted; 

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transOption)) 
{ 
    PurchaseOrder purchaseOrder = GetFull(request.OrderId); 
    purchaseOrder.ChangeTracker.ChangeTrackingEnabled = true; 
    purchaseOrder.IdStatus = DbConstants.RefPurchaseOrderStatus.Completed; 

    //select the quantity of purchased gift cards and update them with ObjectContext.SaveChanges() 
    List<Card> cards = _cardBusiness.AssignCards(purchaseOrder.Quantity, purchaseOrder.IdProduct, purchaseOrder.IdUserAccount, purchaseOrder.IdChannel); 

    Card[] arrCards = cards.ToArray(); 

    int count = 0; 
    //Set a link between a PurchaseOrder Line and the Card 
    foreach(PurchaseOrderLine line in purchaseOrder.PurchaseOrderLines) 
    { 
     line.ChangeTracker.ChangeTrackingEnabled = true; 
     line.IdCard = arrCards[count].Id; 
     count++; 
    } 

    PurchaseOrder po = Update(purchaseOrder); 

    scope.Complete(); 

    return true; 
} 

クイックコメント:トランザクションでは、我々はいくつかのプロパティを編集し、利用できるギフトカード(複数可)を選択し、そのステータスを変更し、以前に挿入PurchaseOrderを取得し、SaveChanges()とリンクにギフトカード(複数可)を返しますPurchaseOrderLine

しかし、私たちは明らかにカード選択をロックしていません。どうしたらいい?

更新:

public static List<Card> AssignCards(int qty, int idProduct, Guid idUserAccount, int? idChannel) 
{ 
    using (RestopolitanEntities context = GetContext()) 
    { 
     try 
     { 
      var Xcards = (from c in context.Cards 
         select c); 

      List<Card> cards = Xcards.OrderBy(c => c.IdOrder).Take(qty).ToList(); 

      foreach (Card card in cards) 
      { 
       card.ChangeTracker.ChangeTrackingEnabled = true; 
       card.UseDate = DateTime.Now; 
      } 

      context.SaveChanges(); 

      return cards.ToList(); 
     } 
     catch (Exception ex) 
     { 
      HandleException(ex); 
     } 
    } 
    return null; 
} 

私はIsolationLevel.RepeatableReadてみました、Cardは長い2 PurchaseOrderに起因していません。ただしAssignCards()からはCardが返されません。同時クリック数が4の場合、Cardを含まないCardと2 PurchaseOrderを区別する2つのPurchaseOrderがあります。

+0

AssignCards()とは何ですか?このメソッドのコードを追加できますか? – MikkaRin

+1

おそらく、あなたはすでに使用されている番号を取得しないようにdbが注意を払うので、データベースシーケンスでソリューションを作成することができます... – DatRid

+0

どのデータベースプラットフォームを使用していますか? – mjwills

答えて

1

どちらか

context.Database.ExecuteSqlCommand("exec sp_getapplock 'AssignCards','Exclusive';"); 

または使用するカードを識別し、クエリにいくつかのロックヒントを使用し、トランザクションの開始時にアプリケーションロックを取得:

var sql = "select top (@qty) CardId from Cards with (rowlock, updlock, readpast) where UseDate is null"; 
var cardIds = context.Database.SqlQuery<int>(sql,qty).ToList(); 

List<Card> cards = context.Cards.Where(c => cardIds.Contains(c.CardId)).ToList(); 

あなたがロックを使用している場合READPASTヒントを使用して、他のセッションによってロックされているカードを並行セッションでスキップすることができます。アプライセーション・ロックを使用すると、トランザクションの途中で(カードを選択した後で)ロックを解除できます。