KingKerosin
KingKerosin

Reputation: 3841

How to avoid rewriting identical using statements?

Is there a way to create a nested using in a Disposable object, so this code:

using (var ctx = new MyEntities())
{
    ctx.Connection.Open();
    using (var tx = dbContext.Connection.BeginTransaction())
    {
        // ... do awesome things here

        ctx.SaveChanges();
        tx.Commit();
    }
}

to something like this:

using (var txContext = new TransactionContext())
{
    // ... do awesome things here
}

?

Currently I have:

public class TransactionContext : IDisposable
{
    private MyEntities DbContext { get; set; }
    private DbTransaction Transaction { get; set; }

    public TransactionContext()
    {
        DbContext = new MyEntities();
        DbContext.Connection.Open();

        Transaction = DbContext.Connection.BeginTransaction();
    }

    void IDisposable.Dispose()
    {
        try
        {
            DbContext.SaveChanges();
            Transaction.Commit();
        }
        catch (Exception exception)
        {
            Transaction.Rollback();
            DbContext.Dispose();
        }
    }
}

I'm not sure if this is correct in ways of disposing the different Disposables, especially in case of an error/exception.

Upvotes: 2

Views: 109

Answers (1)

juharr
juharr

Reputation: 32276

It would probably be better to use a method instead of a class for this.

private static void RunInTransaction(Action<MyEntities, DbTransaction> action)
{
    using (var ctx = new MyEntities())
    {
        ctx.Connection.Open();
        using (var tx = ctx.Connection.BeginTransaction())
        {
            action(ctx, tx);
            ctx.SaveChanges();
            tx.Commit();
        }
    }
}

Then you can call it like this.

RunInTransaction((ctx,tx) => 
{
    // ... do awesome things here
}); 

You can also create a version of this that returns a value

private static T RunInTransactionAndReturn<T>(
    Func<MyEntities, DbTransaction, T> function)
{
    using (var ctx = new MyEntities())
    {
        ctx.Connection.Open();
        using (var tx = ctx.Connection.BeginTransaction())
        {
            var result = function(ctx, tx);
            ctx.SaveChanges();
            tx.Commit();
            return result;
        }
    }
}

Then you can call it like this.

var result = RunInTransactionAndReturn((ctx,tx) => 
{
    // ... do awesome things here
    return someResult;
}); 

Upvotes: 2

Related Questions