13

I am working with a database, and there is a situation where I want to turn off a feature in it. Turning off the feature looks something like this...

DatabaseContext.Advanced.UseOptimisticConcurrency = false;

Turning it on is just as easy. This functions fine. But I was curious about something and wanted to explore it ...

Is it possible to wrap this in a "using" block like we do with things like dispose and unsafe? For instance...

using(DatabaseContext.Advanced.UseOptimisticConcurrency = false){
   // do things!
}

// the feature is turned back on automatically here!

Update

With the help of the great people here at StackOverflow, I have now made the behavior I wanted work perfectly. Thanks again. Here is my working code. Don't mind the verbose documentation. I am just the kind of programmer that types everything in my head out.

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

Then, in my actual code...

    /// <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);
    }
Ciel
  • 4,290
  • 8
  • 51
  • 110
  • 2
    You would need to create a wrapper class that handles this functionality for you to roll it back. – tsells Oct 28 '13 at 19:19
  • So how do I go about that? I once thought this technique was only for disposal, but I've started to see it applied in other places, and it reads really well and clear, so I'd like to give it a try. – Ciel Oct 28 '13 at 19:20
  • 3
    Implement IDispose on a custom class, store original value of UseOptimisticConcurrency in constructor, set new value in constructor, set original value in Dispose method. – Marvin Smit Oct 28 '13 at 19:21
  • Thank you. If I may ask, what is the "actual" name for this kind of behavior? the using block. I had a hard time finding any information on it because I'm unsure of what it is really called. – Ciel Oct 28 '13 at 19:32

6 Answers6

17

Just wrap that in a class that is IDisposable and you can revert the functionality in Dispose function.

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

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

Above code is just example you need to tweak it according to your needs.

Mayank
  • 8,777
  • 4
  • 35
  • 60
  • 2
    While this is a good solution to the issue at hand, it is fundamentally incorrect according to the documentation provided by Microsoft for the `IDisposable` interface. A more correct solution would be to implement a function set similar to `Monitor.Enter` and `Monitor.Exit`. – Michael J. Gray Oct 28 '13 at 19:23
  • I'd define this a sort of abuse of `IDisposable`, althought it's completely allowed, good trick. – Omar Oct 28 '13 at 19:29
  • `IDisposable.Dispose` doesn't have any arguments. You're thinking of the protected `Dispose` method that's commonly called by the public `Dispose` method. – Michael Liu Oct 28 '13 at 19:33
  • @MichaelLiu Fixed, thanks for catching that. Hard to remember everything. – Mayank Oct 28 '13 at 19:34
  • I am a bit confused about how this is 'abuse' of the Disposable method. I am not disagreeing, I just lack the experience to grasp the statement. – Ciel Oct 28 '13 at 19:35
  • @Ciel: See http://stackoverflow.com/a/2103158/1127114 (Eric Lippert was a developer on the Microsoft C# compiler team) – Michael Liu Oct 28 '13 at 19:37
  • @Ciel http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface – Mayank Oct 28 '13 at 19:38
  • Ok. So the basic argument is that, while this works, I am using the `Dispose` method to do something OTHER than 'dispose', in my case, I am using it as an ad-hoc "run when finished" code. Does that about sum it up? – Ciel Oct 28 '13 at 19:39
  • Thank you very much for the help. I posted my finished code up above. – Ciel Oct 28 '13 at 19:51
5

I could think of something like that:

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

And then use it like:

bool b;

b = false; // Do something before the block.

using (new MyUsing(delegate { b = true; })) // Do something after the block.
{
    // Do Things.
}

To match your example, it could look like:

DatabaseContext.Advanced.UseOptimisticConcurrency = false;

using (new MyUsing(delegate { 
    DatabaseContext.Advanced.UseOptimisticConcurrency = true; }))
{
    // Do Things.
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • 1
    This is a really great and creative solution. You probably won't get too many upvotes due to the rarity for a custom using block, but it's great, nonetheless. – oscilatingcretin Jun 12 '15 at 13:44
  • 1
    I also love the way this allows creating a class ONCE, rather than each time a custom dispose action is needed. In my case, I create a METHOD that does the needed stuff, because I use some of those methods several times. Simpler than creating a CLASS for each situation. E.g. `public MyUsing tempOptimistic() { return new MyUsing(delegate { DatabaseContext.Advanced.UseOptimisticConcurrency = true; } ); }`, usage: `using (tempOptimistic()) { ... }`. – ToolmakerSteve Dec 19 '15 at 21:47
  • 1
    Another example: `// Usage: "using (Helper.writingToPath( path )) { ... }"` `public static MyUsing writingToPath( string path ) {` `beginWriteToPath( path );` `return new MyUsing( ` `() => endWriteToPath( path )` `);` `}` – ToolmakerSteve Dec 19 '15 at 21:58
0

You can't use custom usings. However, you can wrap your logic in an own class implementing 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;
        }
    }
}

Then you can use it like this:

using (var scope = new UseOptimisticConcurrencyScope(yourContext))
{
    ...
}
user2674389
  • 1,123
  • 7
  • 8
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
}
JG in SD
  • 5,427
  • 3
  • 34
  • 46
0

I've used something like this in the past. There is more you could build into it but in essence you pass it a delegate in the form of a lambda guarunteed to be invoked at the end of a using block:

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

In this way you don't need a new implementation for every possible flag you want to reset.

using(new Sentry(() => DatabaseContext.Advanced.UseOptimisticConcurrency = false)
{
  //
}
dkackman
  • 15,179
  • 13
  • 69
  • 123
0

All you need is a class like this that gives you a 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.
}

so you can say something like

using ( DatabaseOptions options = new DatabaseOptions()
                                  .IsolationLevel( IsolationLevel.ReadUncommited )
                                  .OptimisticConcurrency( true )
) {
     // do something useful
  }
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • So...while this works it still suffers from the 'not how using was meant to be used' problem like below. If "IsolationLevel" returned a new DatabaseOption object then the original would remain unchanged, so you could pass in a lambda that *used* the original... – Chris Pfohl Oct 28 '13 at 19:32
  • I'm not dogmatic about "how" something was intended to be used. Decide on the syntax you want to represent the solution in and implement it sez I. – Nicholas Carey Oct 28 '13 at 19:36