2011-12-30 4 views
2

を見て、アプリの際にIDocumentSession起動(アプリが閉じられるまで、それを閉じることはありません)を作成するには、私はこれを行うことにより、オプティミスティック同時実行を使用することができます:RavenDBキャッチ22 - 楽観的並行性とRavenDBして他のクライアントからの変更点

public class GenericData : DataAccessLayerBase, IGenericData 
{ 
    public void Save<T>(T objectToSave) 
    { 
     Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave); 
     Session.Store(objectToSave, eTag); 
     Session.SaveChanges(); 
    } 
} 

別のユーザーがそのオブジェクトを変更した場合、保存は正しく失敗します。

しかし、アプリの存続期間中に1つのセッションを使用すると、ドキュメントの他のインスタンス(ジョー、5つのキュービクル)からの変更がドキュメントに表示されます。私もこれを試してみたが、それはジョーの変更のいずれかが表示されませんでした:

public class CustomVariableGroupData : DataAccessLayerBase, ICustomVariableGroupData 
{ 
    public IEnumerable<CustomVariableGroup> GetAll() 
    { 
     return Session.Query<CustomVariableGroup>(); 
    } 
} 

注:私はこれを行うと、私はジョーの変更を見ていない私があれば、今すぐ

return Session.Query<CustomVariableGroup>().Customize(x => x.WaitForNonStaleResults()); 

を他の方法を行って、データベースにアクセスするすべてのメソッド内にIDocumentSessionを作成すると、それに反対の問題が発生します。新しいセッションがあるので、私はジョーの変化を見ることができます。 Buuuuuuut ...私は楽観的な同時性を失う。保存する前に新しいセッションを作成すると、空のGUIDが生成されて失敗します。

Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave); 

何が欠けていますか?各メソッド内またはアプリケーションレベルでセッションを作成しない場合は、正しいスコープは何ですか?オプティミスティックな同時実行性の利点を得るにはどうすればよいですか?は、Session.Query()を実行するときに他人の変更を見ることができますか?

+0

Btw、アプリケーションの種類は何ですか。 WebまたはWindows? –

+0

これはWPF Windowsアプリケーションです。 –

答えて

2

免責事項:私はこれが長期的なアプローチではないことを知っていますので、ここで受け入れられる答えではありません。しかし、今は何かを稼ぐだけで済み、後でリファクタリングすることができます。私はまた、いくつかの人々がこのアプローチでうんざりしていることを知っています、笑、でもそうである。それは働いているようだ。私はすべてのクエリ(新しいセッション)で新しいデータを取得し、楽観的な並行性も同様に働きます。

最後の行は、データアクセスメソッドごとに1つのセッションに戻ったことです。そして、データアクセス方法は、取得/ロード/クエリのいくつかのタイプをしたときに、私は静的辞書でetagsの保存:私はデータを保存していたときに、その後

public IEnumerable<CustomVariableGroup> GetAll() 
{ 
    using (IDocumentSession session = Database.OpenSession()) 
    { 
     IEnumerable<CustomVariableGroup> groups = session.Query<CustomVariableGroup>(); 
     CacheEtags(groups, session); 
     return groups; 
    } 
} 

を、私はキャッシュからのeTagをつかみます。これにより、別のインスタンスがデータを変更した場合に並行処理の例外が発生します。これが必要な処理です。

public void Save(EntityBase objectToSave) 
{ 
    if (objectToSave == null) { throw new ArgumentNullException("objectToSave"); } 

    Guid eTag = Guid.Empty; 

    if (objectToSave.Id != null) 
    { 
     eTag = RetrieveEtagFromCache(objectToSave); 
    } 

    using (IDocumentSession session = Database.OpenSession()) 
    { 
     session.Advanced.UseOptimisticConcurrency = true; 
     session.Store(objectToSave, eTag); 
     session.SaveChanges(); 
     CacheEtag(objectToSave, session); // We have a new eTag after saving. 
    } 
} 

私は絶対にこれを正しい方法で長期的に実行したいと思いますが、その方法はまだわかりません。

編集:私はより良い方法を見つけるまでこれを受け入れるようにします。

2

同じセッションを使用しているため、変更が表示されません。私の他の回答を参照してください詳細

1

ボブ、データを最新表示するたびに新しいセッションを開いてみませんか?

すべてのリクエストに対して新しいセッションを開くことには多くのトレードオフがあります。オプティミスティックな同時実行性(独自のシングルトン辞書内のタグを管理する)のソリューションは、決してそのように使用されることはないことを示しています。

あなたはWPFアプリケーションがあると言っています。さて、起動時に新しいセッションを開きます。ロードして問合せを行いますが、データを更新するまでセッションを閉じないでください(たとえば、注文リスト、顧客、わかりません...)。次に、ユーザーがボタンをクリックした後に、それを更新したいときに、タイマーイベントが発生したかどうかなど)、セッションを破棄して新しいセッションを開きます。それはあなたのために働くのですか?

+0

問題は、オブジェクトのリストを取得するためにDBを呼び出すたびに新しいセッションが必要なことです。確かに、私はDBから最新の情報を入手しないのはどうしてもうまくいかない理由は考えられません。つまり、私は最初に電話をかけているのです。だから、私は基本的にあなたが提案したことをすべてのデータアクセス呼び出しで新しいセッションを開くことによってやっています。 –

+0

さて、クライアント上でキャッシュを無効にする方法があるはずです。少なくとも、 "ShouldCacheRequest"というコンビネーションがありますが、すべてのケースでfalseを返すように設定できますが、テストケースでは機能しません。ここに問題があります:https://github.com/ravendb/ravendb/issues/428 –