12

我正在使用数据库,并且在某些情况下我想关闭其中的功能。关闭该功能看起来像这样......

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);
    }
4

6 回答 6

16

只需将其包装在一个类中IDisposable,您就可以恢复函数中的Dispose功能。

public class SomeClass : IDisposable
{
     public SomeClass()
     {
          DatabaseContext.Advanced.UseOptimisticConcurrency = false;
     }

     public void Dispose()
     {
         DatabaseContext.Advanced.UseOptimisticConcurrency = true;
     }
}

上面的代码只是示例,您需要根据需要对其进行调整。

于 2013-10-28T19:21:21.397 回答
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.
}
于 2013-10-28T19:23:44.197 回答
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))
{
    ...
}
于 2013-10-28T19:23:20.710 回答
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
}
于 2013-10-28T19:25:21.733 回答
0

我过去用过这样的东西。您可以在其中构建更多内容,但本质上您以 lambda 的形式传递给它一个委托,保证在 using 块的末尾被调用:

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)
{
  //
}
于 2013-10-28T19:28:58.767 回答
0

你所需要的只是一个像这样的类,它给你一个流畅的 界面

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
  }
于 2013-10-28T19:30:21.793 回答