LINQ: Passing lambda expression as parameter to be executed and returned by method
C#LinqC# 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:
- Table
can be derived from T, else you will need to pass the source too. - 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.