我正在使用数据库,并且有一种情况我想要关闭其中的功能。关闭该功能看起来像这样......
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
打开它也很简单。这个功能很好。但我对某些事感到好奇,并想探索它......
是否可以将它包装在“使用”块中,就像处理像dispose和unsafe这样的东西一样?例如......
using(DatabaseContext.Advanced.UseOptimisticConcurrency = false){
// do things!
}
// the feature is turned back on automatically here!
在StackOverflow的优秀人员的帮助下,我现在已经完成了我想要的工作。再次感谢。这是我的工作代码。不要介意详细的文档。我只是那种在头脑中输入所有内容的程序员。
using System;
namespace Raven.Client {
/// <summary>
/// Used to emulate a series of transactions without optimistic concurrency in RavenDB
/// </summary>
/// <remarks>
/// This has been flagged as an 'abuse' of the IDisposable interface, which is something I will learn more about
/// and try to find a better solution. The purpose of this class is to make absolutely sure that we never use
/// a document session without optimistic concurrency unless we are completely certain it is what we want. I
/// elected to wrap this in a disposable block because that is an easy convention to remember, and it makes the
/// intention very clear to the others who may see this code.
/// Topics[0]: http://stackoverflow.com/questions/19643266/custom-using-blocks
/// Topics[1]: http://stackoverflow.com/questions/2101524/is-it-abusive-to-use-idisposable-and-using-as-a-means-for-getting-scoped-beha/2103158#2103158
/// Topics[2]: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface
/// </remarks>
public class RavenPessimistic : IDisposable {
private readonly IDocumentSession RavenSession;
/// <summary>
/// Disable optimistic concurrency for this exact session only.
/// </summary>
/// <param name="session"></param>
public RavenPessimistic(IDocumentSession session) {
RavenSession = session;
RavenSession.Advanced.UseOptimisticConcurrency = false;
}
/// <summary>
/// Enable the optimistic concurrency again, so that we do not
/// ever use it unintentionally
/// </summary>
public void Dispose() {
RavenSession.Advanced.UseOptimisticConcurrency = true;
}
}
/// <summary>
/// An extension method to make it more convenient to get to this. This is probably not necessary, but I have been
/// anxious to see how RavenDB handles extension methods.
/// </summary>
public static class RavenSessionExtensions {
public static RavenPessimistic OpenPessimisticSession(this IDocumentSession documentSession) {
return new RavenPessimistic(documentSession);
}
}
}
然后,在我的实际代码中......
/// <summary>
/// Edit the given item prototype.
/// </summary>
/// <param name="model">
/// A unique prototype to edit in the database.
/// </param>
/// <returns></returns>
[HttpPost]
[Route("items/edit/prototype")]
public JsonResult Prototype(Models.Items.Prototype model) {
if (ModelState.IsValid) {
// go through the prototype and make sure to set all of the
// mutation names to it.
foreach (var mutation in model.Mutations) {
mutation.Name = model.Name;
}
// we are updating an entry, instead of creating a new one,
// so temporarily turn off optimistic concurrency since we
// are 100% sure we want to overwrite the existing document.
using (RavenSession.OpenPessimisticSession()) {
RavenSession.Store(model);
RavenSession.SaveChanges();
}
// if this was successful, then return the result to the client
return Json(true, JsonRequestBehavior.AllowGet);
}
return Json(false, JsonRequestBehavior.AllowGet);
}
答案 0 :(得分:12)
只需将其包装在IDisposable
的类中,您就可以恢复Dispose
函数中的功能。
public class SomeClass : IDisposable
{
public SomeClass()
{
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
}
public void Dispose()
{
DatabaseContext.Advanced.UseOptimisticConcurrency = true;
}
}
以上代码只是您需要根据需要进行调整的示例。
答案 1 :(得分:5)
我能想到这样的事情:
public class MyUsing :
IDisposable
{
private Action _disposeAction;
public MyUsing(
Action disposeAction)
{
_disposeAction = disposeAction;
}
public void Dispose()
{
var h = _disposeAction;
_disposeAction = null;
if (h != null)
{
h();
}
}
}
然后使用它:
bool b;
b = false; // Do something before the block.
using (new MyUsing(delegate { b = true; })) // Do something after the block.
{
// Do Things.
}
为了匹配您的示例,它可能看起来像:
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
using (new MyUsing(delegate {
DatabaseContext.Advanced.UseOptimisticConcurrency = true; }))
{
// Do Things.
}
答案 2 :(得分:0)
您无法使用自定义使用。但是,您可以将逻辑包装在一个实现IDisposable的类中。
public class UseOptimisticConcurrencyScope : IDisposable
{
private DatabaseContext _dbContext;
private bool _originalValue;
public UseOptimisticConcurrency(DatabaseContext dbContext)
{
_dbContext = dbContext;
_originalValue = dbContext.Advanced.UseOptimisticConcurrency;
dbContext.Advanced.UseOptimisticConcurrency = false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinaliz(this);
}
public virtual void Dispose(bool disposing)
{
if (disposing)
{
_dbContext.Advanced.UseOptimisticConcurrency = _originalValue;
}
}
}
然后你可以像这样使用它:
using (var scope = new UseOptimisticConcurrencyScope(yourContext))
{
...
}
答案 3 :(得分:0)
public IDisposable DisableOptimisticConcurrency()
{
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
return new DisposeAdapter(() =>
{
DatabaseContext.Advanced.UseOptimisticConcurrency = true;
});
}
public class DisposeAdapter : IDisposable
{
private readonly Action performOnDispose;
private int disposed = 0;
public DisposeAdapter(Action performOnDispose)
{
if (performOnDispose == null)
throw new ArgumentNullException("performOnDispose");
this.performOnDispose = performOnDispose;
}
public void Dispose()
{
if (Interlocked.Exchange(ref this.disposed, 1) == 0)
this.performOnDispose();
}
}
using (DisableOptimisticConcurrency())
{
// perform action
}
答案 4 :(得分:0)
过去我曾经使用过类似的东西。你可以构建它更多,但实质上你传递一个lambda形式的委托,在一个使用块的末尾被调用:
class Program
{
static void Main(string[] args)
{
bool b = false;
using (new Sentry(() => b = false))
{
// do some stuff
b = true;
// do other stuff
}
System.Diagnostics.Debug.Assert(b == false);
}
}
class Sentry : IDisposable
{
private Action _action;
public Sentry(Action disposeAction)
{
_action = disposeAction;
}
public void Dispose()
{
if (_action != null)
_action();
}
}
通过这种方式,您不需要为要重置的每个可能标志创建新的实现。
using(new Sentry(() => DatabaseContext.Advanced.UseOptimisticConcurrency = false)
{
//
}
答案 5 :(得分:0)
您需要的就是这样一个类,它会为您提供fluent interface
public class DataBaseOptions : IDisposable
{
public DataBaseOptions()
{
// save initial state here
}
public DataBaseOptions OptimisticConcurrency( bool state )
{
// set option state
return this ;
}
public DataBaseOptions IsolationLevel( IsolationLevel state )
{
// set option state
return this ;
}
public void Dispose()
{
// restore initial state here ;
}
}
public enum IsolationLevel
{
ReadCommitted = 0 ,
ReadUncommitted = 1 ,
CursorStability = 2 ,
// etc.
}
所以你可以这样说
using ( DatabaseOptions options = new DatabaseOptions()
.IsolationLevel( IsolationLevel.ReadUncommited )
.OptimisticConcurrency( true )
) {
// do something useful
}