RavenDB Catch 22-乐观并发性和查看来自其他客户端的更改

RavenDB Catch 22-乐观并发性和查看来自其他客户端的更改,ravendb,optimistic-concurrency,Ravendb,Optimistic Concurrency,使用RavenDB,在应用程序启动时创建一个IDocumentSession(并且在应用程序关闭之前从不关闭它),允许我通过执行以下操作来使用乐观并发: 公共类GenericData:DataAccessLayerBase、IGenericData { 公共作废保存(T objectToSave) { Guid eTag=(Guid)Session.Advanced.GetEtagFor(objectToSave); Session.Store(objectToSave,eTag); Sessi

使用RavenDB,在应用程序启动时创建一个
IDocumentSession
(并且在应用程序关闭之前从不关闭它),允许我通过执行以下操作来使用乐观并发:

公共类GenericData:DataAccessLayerBase、IGenericData
{
公共作废保存(T objectToSave)
{
Guid eTag=(Guid)Session.Advanced.GetEtagFor(objectToSave);
Session.Store(objectToSave,eTag);
Session.SaveChanges();
}
}
如果其他用户更改了该对象,则保存将正确失败

但是,当在应用程序的生命周期中使用一个会话时,我不能做的是看到应用程序的其他实例(比如,五个隔间之外的Joe)对文档所做的更改。当我这样做时,我看不到Joe的变化:

公共类CustomVariableGroupData:DataAccessLayerBase,ICustomVariableGroupData
{
公共IEnumerable GetAll()
{
返回Session.Query();
}
}
注意:我也尝试过这个,但它也没有显示Joe的更改:

return Session.Query().Customize(x=>x.WaitForNonStaleResults());
现在,如果我换一种方式,在每个访问数据库的方法中创建一个
IDocumentSession
,那么我就会遇到相反的问题。因为我有一个新的会议,我可以看到乔的变化。布乌乌特。。。然后我就失去了乐观的一致性。保存前创建新会话时,此行生成空GUID,因此失败:

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

我错过了什么?如果会话不应该在每个方法中创建,也不应该在应用程序级别创建,那么正确的范围是什么?如何获得乐观并发的好处,以及在执行会话时能够看到其他人的更改。Query()?

您不会看到更改,因为您使用的是同一个会话。有关更多详细信息,请参见我的其他人的回复。

免责声明:我知道这不是一个长期的方法,因此在这里不会是一个可接受的答案。然而,我现在只需要让一些东西工作起来,然后我就可以重构了。我也知道有些人会对这种方法感到厌恶,哈哈,但就这样吧。它似乎起作用了。每次查询(新会话)都会得到新的数据,乐观并发性也能正常工作

底线是,我返回到每个数据访问方法的一个会话。每当数据访问方法执行某种类型的get/load/query时,我都会将etag存储在静态字典中:

public IEnumerable<CustomVariableGroup> GetAll()
{
    using (IDocumentSession session = Database.OpenSession())
    {
        IEnumerable<CustomVariableGroup> groups = session.Query<CustomVariableGroup>();
        CacheEtags(groups, session);
        return groups;
    }
}
从长远来看,我绝对想以正确的方式来做这件事,但我还不知道那是什么方式


编辑:在我找到更好的方法之前,我会让这个答案成为公认的答案。

鲍勃,为什么每次你想刷新数据时不打开一个新的会话呢

为每个请求打开新会话有很多折衷,而您的乐观并发解决方案(在您自己的单例词典中管理标记)表明,它从来没有打算以这种方式使用


你说你有一个WPF应用程序。好的,在启动时打开一个新会话。加载和查询您想要的任何内容,但在您想要刷新数据之前不要关闭会话(例如,订单列表、客户、我不知道……)。然后,当您想要刷新会话时(在用户单击按钮后,会触发计时器事件或其他事件),请处理会话并打开一个新会话。这对你有用吗?

顺便问一下,你的应用程序是什么类型的。Web还是Windows?问题是每次调用DB获取对象列表时,我都需要一个新会话。事实上,我想不出为什么不从DB获得最新信息是可以的。我是说,这就是我为什么要打电话的原因。所以,我基本上是按照您的建议,在每次数据访问调用时打开一个新会话。好的,应该有一种方法来禁用客户端上的缓存,至少有一个转换“ShouldCacheRequest”,您可以在任何情况下都设置为返回false,但是它在我的测试用例中不起作用,所以我在这里打开了一个问题:
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.
    }
}