1

This is my scenario: I need to extract data from an entity using an "OR" query on a a property in a linked entity.

These are my entities:

public class Dealer
{
  public virtual int id{get;set;}
  public virtual string name{get;set;}
  public virtual IList<Car> Cars{get;set;}
}

public class Car 
{
  public virtual int id{get;set;}
  public virtual string name{get;set;}
  public virtual int kw{get;set;}
}

Example: I want to extract all dealers that have cars with 98kw or 100kw. Sql Example:

SELECT Dealers.* FROM Dealers INNER JOIN Cars ON Cars.IdDealer = Dealers.Id WHERE Cars.kw = 98 OR Cars.kw = 100

I tried to use Expression trees but i don't know how to use them. I tried this:

var dealers = Session.Linq<Dealers>();
ParameterExpression pe = Expression.Parameter(typeof(int), "kw");
Expression tot = null;
var powers = new int[2]{98, 100};

for (var i = 0; i < powers.Length; i++)
{
    Expression right = Expression.Constant(int.Parse(powers[i]));
    if (i > 0)
        tot = Expression.Or(tot, Expression.Equal(pe, right));
    else
        tot = Expression.Equal(pe, right);
}
dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, null)));

but i get these compiler errors on the last row where I try to execute the Expression:

  • Cannot convert lambda expression to type string because it is not a delegate type
  • System.Collections.Generic.IList<Cars> does not contain a definition for Any and the best extension method overload System.Linq.Enumerable.Any(System.Collections.Generic.IEnumerable, System.Func) has some invalid arguments
  • Argument 2: cannot convert from System.Linq.Expressions.Expression<System.Func<Cars,bool>> to System.Func<Cars,bool>

Any suggestions?

Albirex
  • 283
  • 1
  • 2
  • 13
  • What "compiler error"? – Konrad Morawski Jan 24 '14 at 09:38
  • can i make a little suggestion which may or may not be greeted with joy. in my opinion, you should avoid using RAW expressions in that fashion in an open environment. i would heartily suggest that you adopt a more closed approach and look at something like the albahari predicatebuilder: http://www.albahari.com/nutshell/predicatebuilder.aspx will save you lots of frustration. some great working examples on the page too – jim tollan Jan 24 '14 at 09:42
  • @KonradMorawski added error list in question – Albirex Jan 24 '14 at 09:44

3 Answers3

2

as per the comment that i left:

... can i make a little suggestion which may or may not be greeted with joy. in my opinion, you should avoid using RAW expressions in that fashion in an open environment. i would heartily suggest that you adopt a more closed approach and look at something like the albahari predicatebuilder: albahari.com/nutshell/predicatebuilder.aspx will save you lots of frustration. some great working examples on the page too

I can't emphasize enough the benefits that this has given many projects that we've undertaken. The usage of this library/approach translates to expressions along the lines of:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}

etc. Thus, you can build pretty complex statements will all the internals hidden away. This makes complete sense, especially if you may have more junior devs working on the code now or in the future. I strongly urge you to indulge your curiousity and wander over to the link and get a better feel from there.

jim tollan
  • 22,305
  • 4
  • 49
  • 63
1

try change your code like this

var dealers = Session.Linq<Dealers>();
ParameterExpression pe = Expression.Parameter(typeof(Car), "c");
var kw = Expression.Property(pe, "kw");
var powers = new string[2]{"98", "100"};

Expression tot = powers.Select(p=>Expression.Constant(int.Parse(p)))
                       .Select(p=>Expression.Equal(kw,p))
                       .Aggregate((a,b)=>Expresion.Or(a,b));

also you need change your Cars declaration to IEnumerable<Car> or IQueriable<Car>

If IEnumerable<Car> then call it like

dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, pe).Compile()));

If IQueriable<Car> then call it like

dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, pe)));
Grundy
  • 13,356
  • 3
  • 35
  • 55
0

Cast the result of Expression.Lambda to

Expression<Func<Car, bool>>

and you need to pass in the parameter expression:

x.Cars.Any( ( Expression<Func<Car, bool>> )Expression.Lambda<Func<Cars, bool>>( tot, pe ) )
Moho
  • 15,457
  • 1
  • 30
  • 31