0

I am working in creating a generic method that allows me to include inside a transaction scope each of the operations of the database. Currently I have multiple LINQ to SQL operations in my code such as:

var myVar = MyContext.First(c => c.Id == myId);

What I have right now are generic methods for each of the possible operations such as Count, First, FirstOrDefault, ToList, etc:

public static TSource FirstReadUncommitted<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate = null)
    {
        var transactionOptions = new TransactionOptions()
        {
            IsolationLevel = IsolationLevel.ReadUncommitted
        };
        TSource outputItem;
        using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
        {
            outputItem = predicate != null ? source.First(predicate) : source.First();
            scope.Complete();
        }
        return outputItem;
    }

However, I would like a more generic approach in which I can somehow pass as an argument the method I want to apply to the query as follows:

public static TSource ReadUncommittedFunction<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate = null, Function????? function)
        {
            var transactionOptions = new TransactionOptions()
            {
                IsolationLevel = IsolationLevel.ReadUncommitted
            };
            TSource outputItem;
            using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
            {
                outputItem = predicate != null ? source.function(predicate) : source.function();
                scope.Complete();
            }
            return outputItem;
        }

Is this possible? What would be the type of the function argument?

On a more complicated approach, I would like to send into the above mentioned method a list of operations to be performed inside my scope (because the transaction may consist of multiple operations). Is this possible?

public static TSource ReadUncommittedFunctions<TSource>(FunctionList functionList)
        {
            var transactionOptions = new TransactionOptions()
            {
                IsolationLevel = IsolationLevel.ReadUncommitted
            };
            TSource outputItem;
            using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
            {
                source.functionList.ElementAt(0)();
                source.functionList.ElementAt(1)();
                scope.Complete();
            }
            return outputItem;
        }
luisgepeto
  • 763
  • 1
  • 11
  • 36

2 Answers2

0

You can try by using a generic Func, like this:

public static TSource ReadUncommittedAction<TSource>(Func<TSource> func)
{
  var transactionOptions = new TransactionOptions()
  {
      IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
  };
  TSource outputItem;
  using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
  {
      outputItem = func();
      scope.Complete();
  }
  return outputItem;
}

And then:

ReadUncommittedAction<SomeClass>(() => 
{
    // as many actions as needed
    return new SomeClass();
});
thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • I think this causes loss of functionality because the OP can no longer pass in the optional predicate. I think you can fix by adding the predicate variable back to the ReadUncommitedAction argument list and use a Func>> instead. – user700390 Mar 23 '15 at 16:49
0

Well. I could think of a couple of approaches to what, I think, you want.

Firstly, I suppose you could pass along the name of the function(s) you want to invoke on your 'source' inside the scope and use reflection to invoke the correct method. Much like in this post:

Calling a function from a string in C#

Or, you could do the same as your predicate... Extend 'ReadUncommittedFunctions' function to take an extra Func as an argument. The Func would take the scope and predicate as the input and TSource as output. Inside the Func you apply the desidered operation on the scope and return the result. 'ReadUncommittedFunctions' would then invoke the Func inside the using block.

Just a suggestion though.

Community
  • 1
  • 1
Frode
  • 389
  • 3
  • 4