Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to wrap a method with a constant code from inside of it?

I have many database queries that I'd like to wrap inside of the same try-catch style error handler. Trying to keep a code DRY I figured it would be effective to do something like this but i couldn't find anything similar. Is there any other approach or is it possible to do exactly this?

I'd like to make an outside method like this:

try
{
    // I would like to put any method here
}
catch (DbEntityValidationException)
{
    // Error handling
}
catch(DbUpdateException)
{
    // Error handling
}
catch (InvalidOperationException)
{     
    // Error handling
}
    catch (EntityException)
{
    // Error handling
}

And where "// I would like to put any method here" is I would like to put a method like this:

public DatabaseResultEnum DoSmth(int someId)
{
    using ( var context = new TestingDatabaseEntities() )
    {
        // Any database action
    }
}

and it would be really convenient to just call the inside ("DoSmth()") method instead of putting an action in the first one, and then passing parameters into it like in this example: Generic Function wrapper

Thanks in advance!

like image 432
jurgis Avatar asked Aug 31 '25 22:08

jurgis


2 Answers

Use a delegate.

So the caller would use code like:

result = ExceptionChecker((context) => {
           // do something with the DbContext context
           return results...
         });

Where you then have

IEnumerable<TRes> ExceptionChecker<TRes>(Func<MyDbContext, IEnumerable<TRes>> function) {
  try {
    using (var ctx = new MyDbContext(...)) {
      return function(ctx);
    }
  } catch (InvalidOperationException) {
    // Handle...
  } // etc.
}

Of course, real code should be using async/await to avoid blocking threads on long running queries. And ideally you would manage the context instances better to make use of EF's support for the unit of work pattern (eg. have a single context per web request) in which case the DbContext instance is passed to the helper. But this shows the approach.

like image 56
Richard Avatar answered Sep 03 '25 13:09

Richard


Yes, it is possible.

public T DoSomething(Func<TestingDatabaseEntities, T> func)
{
    try
    {
     using ( var context = new TestingDatabaseEntities() )
        {
            // Any database action
            return func(context);
        }
    }
    catch (DbEntityValidationException)
    {
        // Error handling
    }
    catch(DbUpdateException)
    {
        // Error handling
    }
    catch (InvalidOperationException)
    {     
        // Error handling
    }
    catch (EntityException)
    {
        // Error handling
    }
}

And then to consume:

public DatabaseResultEnum DoSmth(int someId)
{
    return this.DoSomething(context => context
               .DatabaseResultEnum.FirstOrDefault(y => y.Id == someId));
}
like image 27
zaitsman Avatar answered Sep 03 '25 14:09

zaitsman