2016-11-11 1 views
0

私は奇妙な問題に直面しています。ユーザーが自分のWebアプリケーションの任意のページにアクセスしたときには、 にアクセスする権限があるかどうかを確認し、初めてアクセスする場合は試用期間を提供します。ここでEF Count()> 0しかしFirst()例外をスローする

は、コードの私の作品です:

ここ
List<string> temp_workers_id = new List<string>(); 
... 
if (temp_workers_id.Count > 6) 
       { 
        System.Data.SqlTypes.SqlDateTime sqlDate = new System.Data.SqlTypes.SqlDateTime(DateTime.Now.Date);  
var rusers = dbctx.tblMappings.Where(tm => temp_workers_id.Any(c => c == tm.ModelID)); 
    var permissions = dbctx.UserPermissions 
     .Where(p => rusers 
      .Any(ap => ap.UserID == p.UserID) 
      && p.DateStart != null 
      && p.DateEnd != null 
      && p.DateStart <= sqlDate.Value 
      && p.DateEnd >= sqlDate.Value); 

    if (permissions.Count() < 1) 
    { 
     permissions = dbctx.UserPermissions 
      .Where(p => rusers 
      .Any(ap => ap.UserID == p.UserID) 
       && p.DateStart == null 
       && p.DateEnd == null); 

     var used = dbctx.UserPermissions 
      .Where(p => rusers 
      .Any(ap => ap.UserID == p.UserID) 
       && p.DateStart != null 
       && p.DateEnd != null); 

    if (permissions.Count() > 0 && used.Count() < 1) 
    { 
     var p = permissions.First(); 
     using (Models.TTTDbContext tdbctx = new Models.TTTDbContext()) 
     { 
       var tp = tdbctx.UserPermissions.SingleOrDefault(tup => tup.UserID == p.UserID); 
       tp.DateStart = DateTime.Now.Date; 
       tp.DateEnd = DateTime.Now.Date.AddDays(60); 
       tdbctx.SaveChanges(); 
     } 

First()メソッドが例外をスロー:

シーケンスはそれも可能性がどのように要素

が含まれていませんか?

EDIT: ユーザーが2つのブラウザを開いて同時に移動するとは思えませんが、並行性の問題がありますか?

+3

morcodeを入力してください。パーミッションとは何ですか? –

+0

あなたは許可抽出でDefaultIfEmptyを使用していますか? –

+0

多くのコードが追加されました、いいえDefaultIfEmpty – okarpov

答えて

1

これはサーバーログでのみ見つかりましたが、デバッグ中はこのエラーが発生していないと主張しました。クエリはもはやに一致する情報は見つかりませんでしたように、

if (permissions.Count() > 0) 
{ 
    var p = permissions.First(); 

他のいくつかのプロセスまたはスレッドは、データベースを変更する:つまり、これらの線の間にあることを意味します。

これは、遅延評価リソースを保持するpermissionsが原因で発生します。つまり、クエリを繰り返し実行するときに実行されます(Count()およびFirst())。

のでCount()に、クエリが実行されます。

SELECT COUNT(*) ... WHERE ... 

、その瞬間に、1行を返します。次いで、データは、(First()で)次のクエリを引き起こし、外部から修正される:

SELECT n1, n2, ... WHERE ... 

ゼロ行を返すには、スローするFirst()を引き起こします。

これを解決する方法は、あなた次第です。このシナリオをどのようにモデル化するかによってまったく異なります。つまり、にはという瞬間には、クエリ条件を満たす行がもうなくなっています。クエリを一度具体化することができます:

permissions = query.Where(...).ToList() 

しかし、それはあなたのロジックが古いデータで動作することを意味します。あなたがFirstOrDefault()を使用したい場合にも、同じことが起こるでしょう:

var permissionToApply = permissions.FirstOrDefault(); 
if (permissionToApply != null) 
{ 
    // rest of your logic 
} 

だから、基本的には負け - 負けたシナリオです。古いデータで操作している可能性は常にあります。つまり、次のコードが表示されます。

スローされます。したがって、データベースに問い合わせるたびに、存在しないレコードを処理できるようにコードを記述する必要があります。