Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reuse a linq expression for 'Where' when using multiple source tables

Tags:

c#

linq

Let's have the following:

public interface IOne {
    UInt64 Id { get; }
    Int16 Size { get; }
}

public interface ITwo {
    UInt64 OneId { get; }
    Int16 Color { get; }
}

As explained here the way to reuse a linq expression is to write something like this:

public static Expression<Func<IOne, bool>> MyWhereExpression( int value ){
    return (o) => (o.Size > value);
}

int v = 5;
IQueryable<IOne> records = from one in s.Query<IOne>()
                                        .Where(MyWhereExpression(v))
                           select one;

When I want to do the same with two tables I encounter a problem.

The expression:

public static Expression<Func<IOne, ITwo, bool>> MyWhereExpression2(int color ) {
    return (one,two) => (one.Id == two.OneId) && (two.Color > color );
}

Linq 1:

int color = 100;
IQueryable<IOne> records = from one in s.Query<IOne>()
                           from two in s.Query<ITwo>()
                                        .Where(MyWhereExpression2(color))
                           select one;

This doesn't work as .Where sticks to only the 2nd from.

Linq 2:

int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
                            from two in s.Query<ITwo>()
                            select new { one, two })
                           .Where(MyWhereExpression2(color));

This results in

Argument 2: cannot convert from 'Expression<System.Func<IOne,ITwo,bool>>' to 'System.Func<AnonymousType#1,int,bool>'

I understand the error message about the AnonymousType, but I cannot figure out how to write the query.

The reason why I want to use an expression rather than just write

where (one.Id == two.OneId) && (two.Color > color ) 

directly in the linq query is because I want to reuse this expression in multiple linq queries.

like image 203
tymtam Avatar asked Nov 25 '11 02:11

tymtam


People also ask

What is LINQ why is it used give an example for the same?

LINQ applies the principles of object-oriented programming to relational data. It provides a unified programming model for querying data from different types of data sources, and extends data capabilities directly into the C# and Visual Basic languages. For more information, see Language-Integrated Query (LINQ).

What is let clause in LINQ?

The Let keyword allows you to create a range variable and initialized with the result of the query expression and then you are allowed to use that variable with the upcoming clause in the same query.

How many ways can you write the LINQ query?

LINQ provides you three different ways to write a LINQ query in C# or VB.


1 Answers

There may be a more elegant solution that escapes me at the moment, but you could just use Tuple<IOne, ITwo> instead of the anonymous type:

static Expression<Func<Tuple<IOne, ITwo>, bool>> MyWhereExpression2(int color) {
    return t => (t.Item1.Id == t.Item2.OneId) && (t.Item2.Color > color);
}

int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
                            from two in s.Query<ITwo>()
                            select Tuple.Create(one, two))
                            .Where(MyWhereExpression2(color))
                            .Select(t => t.Item1);

UPDATE: I probably answered too quickly above as that won't work with Linq to SQL since the call to Tuple.Create cannot be translated to SQL. To work with Linq to SQL, the only solution I see at the moment is to create a named type:

class Pair
{
    public IOne One { get; set; }
    public ITwo Two { get; set; }
}

static Expression<Func<Pair, bool>> MyWhereExpression2(int color) {
    return p => (p.One.Id == p.Two.OneId) && (p.Two.Color > color);
}

int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
                            from two in s.Query<ITwo>()
                            select new Pair { One = one, Two = two })
                            .Where(MyWhereExpression2(color))
                            .Select(p => p.One);
like image 65
Nick Guerrera Avatar answered Sep 28 '22 17:09

Nick Guerrera