C
C#•3mo ago
sideburns_01

Passing Lambda as a method parameter: Some issues

I am building an IQueryable extension that can perform queries on nested object properties (that is the hope). I would like to apply this extension to a class, then pass the desired nested object to the extension to further build a where clause Here is an example of how I would call the extension: _context.ClassA.CustomExtension(a => a.ClassB) (ClassB is an object instance on Class A) All examples online show some expression that returns a value, however in this case I don't have one. I just want the extension to know it should query this nested Class on _context.ClassA. Not sure how to set up the parameter. What is the correct way to go about this?
7 Replies
mldisibio
mldisibio•3mo ago
If I understand you correctly, you want to pass in a Function that knows how to query your nested property, but you probably need a generic parameter to specify the expected outcome:
void Main()
{
Bar b = new Bar("abc", new Foo("Joe", 37));
Console.WriteLine(b.QueryProperty(b => b.Person.Age));
Console.WriteLine(b.QueryBarProperty(b => b.Person.Name));
}

public record Foo(string Name, int Age);
public record Bar(string Tag, Foo Person);
public static class Ext
{
// specific to Bar
public static TOut QueryBarProperty<TOut>(this Bar src, Func<Bar, TOut> query) => query(src);
// any class
public static TOut QueryProperty<TIn, TOut>(this TIn src, Func<TIn, TOut> query) => query(src);
}
void Main()
{
Bar b = new Bar("abc", new Foo("Joe", 37));
Console.WriteLine(b.QueryProperty(b => b.Person.Age));
Console.WriteLine(b.QueryBarProperty(b => b.Person.Name));
}

public record Foo(string Name, int Age);
public record Bar(string Tag, Foo Person);
public static class Ext
{
// specific to Bar
public static TOut QueryBarProperty<TOut>(this Bar src, Func<Bar, TOut> query) => query(src);
// any class
public static TOut QueryProperty<TIn, TOut>(this TIn src, Func<TIn, TOut> query) => query(src);
}
sideburns_01
sideburns_01•3mo ago
Hi. thanks for getting back to me. What I'm trying to do is create a dynamic extension query that can encapsulate the where statement in_context.ClassA.Where(a => a.ClassB.someVal == someReferenceVal). I was working with Expressions trees, and the problem there is getting the nested object and its propery to build that where clause. Not sure how to go about it. Though I am open to other ideas if my initial idea is wrong. The key idea being what options exist to encapsulate the .Where(a => a.ClassB.someVal == someReferenceVal)
mldisibio
mldisibio•3mo ago
Ah, so you are really building the IQueryable! I got frustrated in my attempts years ago, but have a look at Joe Albahari's approach here: https://www.albahari.com/nutshell/linqkit.aspx
sideburns_01
sideburns_01•3mo ago
ok, thanks for the reference. I was trying to build something like this using expressions rather than sql syntax private sealed class referenceValue<T> { public int Value {get; set;} } public static IQueryable<T> WithIdExtension<T>(this IQueryable<T> query) where T : class { //entity we are applying filter to var memberEntity = Expression.Parameter(typeof(T)) //the property we want to access var accessEntityProperty = Expression.PropertyOrField(memberEntity, "SpecificId') var objectValue = new referenceValue<T> {Value = someInternalMethod.GetValue()} //this will parameterize value when converted to sql var value = Expression.PropertyOrField(Expression.Constant(objectValue, "Value"); var equalExpression = Expression.Equal(accessEntityParameter, value) Expression<Func<T, bool>> whereLambda = Expression.Lambda<Func<T, bool>>(equalExpression, memberEntity) return query.Where(whereLambda) } dunno if reflection could be used to search for the nested Object class once I got the type T is?
mldisibio
mldisibio•3mo ago
I'm familiar enough with what you are doing to re-iterate that Albahari should be a gold-standard reference. But I gave up on this approach about ten years ago and went with explicit SQL and some extensions that wrapped simple Ado.Net operations with a fluent api. I won't be able to help you much with the Visitor pattern and expression tree builder needed here. 😕
sideburns_01
sideburns_01•3mo ago
ok. Thanks again for the reference, that is very helpful. I will take a deep dive into that.
mldisibio
mldisibio•3mo ago
I'm curious though. Is this going against an RDBMS table, or is it Linq-to-Entity, or is it against a document database? If ClassB is a nested property of ClassA, does your query presume a join clause?