RavenDB Catch 22-乐观并发性和查看来自其他客户端的更改
使用RavenDB,在应用程序启动时创建一个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
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.
}
}