2

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.

4
  • 1
    I'd say the main problem with this design is that it's using the disposable pattern for more than just disposing. If an exception happens in your using then Dispose will be called and now you are calling SaveChanges and Commit when you probably shouldn't. Please read the MSDN article on the dispose pattern Commented Sep 11, 2015 at 13:36
  • 1
    Side note: do not just swallow exceptions: catch (Exception) {... throw;} Commented Sep 11, 2015 at 13:46
  • @juharr: Valid point. Did you have any other solution in mind? At the end it is just to save me from writing the same lines over and over again Commented Sep 11, 2015 at 13:48
  • @KingKerosin I've done something similar, but instead of a class I create a method that contained the basic template and took a Action. Then you just write the code that is different as a lambda and pass it to the method. Commented Sep 11, 2015 at 13:52

1 Answer 1

2

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; }); 
Sign up to request clarification or add additional context in comments.

4 Comments

I will go this (method-based) way. Thanks
@KingKerosin you should be aware that it's impossible to use ref and our parameters inside lambdas. I would stick to your IDisposable method instead.
@Vlad There's nothing here about ref or out parameters and IMHO you should avoid ref and out, not lambdas.
@juharr "There's nothing here about ref or out" I just said that in case one wants to use them it would be impossible to do so inside lamdas. IMHO you should expect any language features to be used in some situations and avoid blocking them.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.