LINQ: Passing lambda expression as parameter to be executed and returned by method

C#Linq

C# Problem Overview


So here is the scenario: i have a series of different repository classes that each can use an isolated data context, or a shared context. In the cases where an isolated context is being used i want to add a method to the base class that will allow me to specify the lambda as the parameter, have that expression be executed by the isolated context of the chosen repository and return an IQueryable result. How would the method signature look, and how to a pass the expression to the context?

I need the solution to be as generic as possible as any possible model object/table could be used.

Here is basically what i am looking to do:

IAssetRepository repo = new AssetRepository(true); // true indicates isolated context
var results = repo.ExecuteInContext<SomeType>(SomeTable.Where(x => 
                                              x.SomeProp.Equals(SomeValue)));

C# Solutions


Solution 1 - C#

Something like this:

public IEnumerable<T> ExecuteInContext<T>(
  Expression<Func<T,bool>> predicate)
{
  ... // do your stuff
  //eg
  Table<T> t = GetTable<T>();
  return t.Where(predicate);
}

or

public IEnumerable<T> ExecuteInContext<T>(
   IQueryable<T> src, Expression<Func<T,bool>> predicate)
{
  return src.Where(predicate);
}

Usage:

var r = repo.ExecuteInContext<SomeType>( 
          x => x.SomeProp.Equals(Somevalue));

or

var r = repo.ExecuteInContext(GetTable<T>(), 
          x => x.SomeProp.Equals(Somevalue));

Assumptions:

  1. Table can be derived from T, else you will need to pass the source too.
  2. You know how to modify the predicate expression if needed.

Solution 2 - C#

Here is a complete working sample how to pass LINQ expression as a parameter

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleTest
{
    public class Values
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override string ToString()
        {
            return String.Format("[ X={0} Y={1} ]", X, Y);
        }
    }

    class Program
    {
        static void Main()
        {
            var values = new Values {X = 1, Y = 1};

            // pass parameter to be incremented as linq expression
            IncrementValue(values, v => v.X);
            IncrementValue(values, v => v.X);
            IncrementValue(values, v => v.Y);

            // Output is: [ X=3 Y=2 ]
            Console.Write(values);
        }

        private static void IncrementValue<T>(T obj, Expression<Func<T,int>> property)
        {
            var memberExpression = (MemberExpression)property.Body;
            var propertyInfo = (PropertyInfo)memberExpression.Member;
            // read value with reflection
            var value = (int)propertyInfo.GetValue(obj, null);
            // set value with reflection
            propertyInfo.SetValue(obj, ++value, null);
        }
    }
}

Solution 3 - C#

Check out PredicateBuilder - http://www.albahari.com/nutshell/predicatebuilder.aspx

This code will package up your where clause as Expression objects which you can pass about.

I've implemented the Repository pattern, and my flava is to give it a Fetch(ICriteria) method, which builds up the Where clause depending on the criteria supplied. Simple, but works for me.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJason MiesionczekView Question on Stackoverflow
Solution 1 - C#leppieView Answer on Stackoverflow
Solution 2 - C#Maksym KozlenkoView Answer on Stackoverflow
Solution 3 - C#DuncanView Answer on Stackoverflow