2017-09-11 3 views
0

私は、プロファイルという名前のテーブルにカウンタフィールドがあり、フォーム送信時にカウンタフィールドを取得し、カウンタと更新プロファイルに+1します表。インクリメントされたカウンタは変数に格納され、別のテーブル[Bidder]に新しいレコードを作成するために使用されます。問題は、複数のフォームがレコード値を複製し、同時にそこに提出されたときである私は、重複ROIDを作成する防ぐにはどうすればよい入札者テーブルentityframeworkを使用してdbから重複する値を取得しないようにする方法

Profile profile = db.Profile.Where(w => w.TenderId == tender_Id && w.IsDeleted == false).FirstOrDefault(); 
int submission = profile.TotalSubmission + 1; 

if (profile != null) { 
    profile.TotalSubmission = submission; 
    profile.ModifiedBy = user_id; 
    profile.ModifiedOn = DateTime.Now; 
    db.Entry(profile).State = EntityState.Modified; 
    db.SaveChanges(); 
} 

bid.ROId = string.Format("RO{0}", submission); 
db.Entry(bid).State = EntityState.Modified; 
db.SaveChanges(); 

に作成されますか?

+2

列に一意のインデックスを作成します。または、より良い、IDの列を使用 – Rhumborl

+0

@ Rhumborl、どのテーブルですか?プロフィールまたは入札ですか? – KylE

+1

コードを変更せずに直接問題を解決する "ロック"でコードを囲むことができます。 @Rhumborlが言ったように、データベースを使用してキーを生成する(つまり、SQL ServerのID列の場合)というユニークなIDを作成するための異なるアプローチを検討することをお勧めします。 –

答えて

0

一意性は、一意のインデックスまたは一意の制約を使用して適用する必要があります。

あなたは(MSDNから)最初のこれらの使用してコードを作成することができます。データベースを介した

public class User 
{ 
    public int UserId { get; set; } 

    [Index(IsUnique = true)] 
    public string Username { get; set; } 

    public string DisplayName { get; set; } 
} 

または直接に。

カウンタは、オプティミスティック同時実行を使用して保護する必要があります。

public class MyEntity 
{ 
    [Key] 
    public Guid Id { get; set; } 

    // Add a timestamp property to your class 
    [Timestamp] 
    [Required] 
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    [ConcurrencyCheck] 
    public byte[] VersionTimestamp { get; set; } 

    public int Counter { get; set; } 
} 

あなたはそれがデータベースから再読み込みそれなしに変更された後VersionTimestampで行を更新しようとした場合、あなたはOptimisiticConcurrencyExceptionを取得します例えばこのテストシナリオでは:あなたは、SQL Server 2012の以降を使用している場合

// Read the entity 
MyEntity entity; 
using (var context = new MyContext()) 
{ 
    entity = context.MyEntities.Single(e => e.Id == id1); 
} 

// Read and update the entity 
using (var context = new MyContext()) 
{ 
    var entity2 = context.MyEntities.Single(e => e.Id == id1); 
    entity2.Counter++; 
    context.SaveChanges(); 
} 

// Try to update stale data 
// - an OptimisticConcurrencyException will be thrown 
using (var context = new MyContext()) 
{ 
    entity.Counter++; 
    context.SaveChanges(); 
} 
0

ソリューションのエンティティフレームワークのみに依存することはできません。データベースのみが、格納されたデータの完全な画像を有する。異なるエンティティ・コンテキスト・インスタンスでは、他のインスタンスが存在するかどうかわからないため、EFレベルでグローバル・スケールでの順序番号の調整は非常に困難です。データ

を書き込むため

  1. ユニーク制約
  2. ストアドプロシージャ:

    は、紛争の頻度に応じて、2つのオプションがシーケンス番号の一意性を強制するために私の心に来て一意の制約

    tを超えてUNIQUE制約を作成できます彼はProfileIdSequenceの列です。重複したシーケンス番号を持つデータを保存すると、例外が発生します。例外自体またはその内部例外のいずれかがSqlExceptionになります。その例外のエラー番号を調べることができ、error number 2627(DBMSがSQL Serverの場合は、そうでない場合は、DBMSで同様のエラーが発生していないかどうかを確認してください)、ユニークなキー制約違反です。この場合、DBから現在のシーケンス番号を取得し、新しいシーケンスでデータを再度書き込みます。挿入が成功するまでそれを繰り返す必要があります。

    SQL Serverを使用している場合は、あなたが選択(C#6.0の例外フィルターを使用して)このようなUNIQUE KEY制約違反を処理することができます:競合の数が予想される場合

    private bool IsUniqueKeyViolation(Exception exception) { 
        Exception currentException = exception; 
        while (currentException != null) { 
         SqlException sqlException = exception as SqlException; 
         if (sqlException != null) { 
          return sqlException.Errors.Cast<SqlError>().Any(error => error.Number == 2627); 
         } 
         currentException = currentException.InnerException; 
        } 
        return false; 
    } 
    
    //... 
    
    //...Code to set up the POCOs before Save... 
    while(true) { 
        try { 
         context.SaveChanges(); 
        } 
        catch(Exception exc) when (IsUniqueKeyViolation(exc)) { 
         //...Code to update the sequence number... 
         continue; 
        } 
        break; 
    } 
    

    このソリューションは、実用的です小さくて競合の数が多い場合は、DBへの多くの失敗した要求が表示されます。これはパフォーマンス上の問題となります。

    EDIT:いくつかの他の回答が示唆したように

    、あなたはまた、タイムスタンプ列との楽観的同時実行を使用することができます。限り、あなた自身のコードからDBを更新する限り、これは正常に動作します。ただし、UNIQUE KEYという制約は、アプリケーションから発生していない変更(移行スクリプトなど)からもデータの整合性を保護します。オプティミスティックな並行性は、あなたに同じ保証を与えません。

    あなたは同じINSERTUPDATE文で既存の最後の番号から新しいシーケンス番号を設定しますストアドプロシージャを作成することができます

    ストアドプロシージャの。ストアドプロシージャは、新しいシーケンス番号をクライアントに返すことができ、それに応じてそれを処理することができます。

    このソリューションでは、1つのステートメントで常にDBが更新されるため、より多くの競合する更新プログラムに対してうまく機能します。欠点は、プログラムロジックの一部をSQLでDBレベルで記述する必要があることです。

+0

これは間違っています - Entity Frameworkはコードファーストで一意のインデックスを作成できます。また、DDDで作業している場合、DBはアプリケーションによって完全に制御されており、アプリケーションはデータベースではなく画像全体を持つものです。 –

+0

?ユニークなインデックス/キーがコードまたはDBで最初に作成された場合、DBは気にしますか?そして、DBがどのように動作するかを設計アプローチがどのように変えるのでしょうか?あなたは、ランタイム問題のための設計時間を話しています。 – Sefe

+0

私の問題は、最初にコードを使用してEFで解決できるので、「あなたはソリューションのエンティティフレームワークにのみ依存できません」というステートメントを使用しています。 –

0

、あなたはこれを達成するためにSequenceを使用することができます。ユニーク制約を使用して一意性を強制したい場合もあります。

public partial class YourEfContext : DbContext 
{ 
    .... (other EF stuff) ...... 

    // get your EF context 
    public int GetNextSequenceValue() 
    { 
     var rawQuery = Database.SqlQuery<int>("SELECT NEXT VALUE FOR dbo.SomeSequence;"); 
     var task = rawQuery.SingleAsync(); 
     int nextVal = task.Result; 

     return nextVal; 
    } 
} 

また、シーケンスをサポートするバージョンがない場合は、データベース上のストアドプロシージャを使用してID番号を発行することもできます。格納されたprocは、明示的にロックをかけることができるIDテーブルと連携して動作することができます。これは、procからIDを要求できることを意味し、テーブルをロックし、現在の数値を読み込み、インクリメントし、テーブルに戻して格納し、ロックを解放し、idを返すことができます。新しいIDを取得するには、コードからprocを呼び出す必要があります。 db側のロックにより、一意の値だけが割り当てられます。あなたのidカラムにprocによって割り当てられた値が与えられている限り、あなたは一意の値を持ちます。ユニークな制約で解決できる、重複を含む可能性のある任意の数を割り当てることができます。

これはEntity-Framework固有のものではありませんが、エンティティフレームワークを通じてこれまでどおりにアクセスできます。

関連する問題