Using predicate builder to build an expression for a range

Posts   
 
    
Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 13-May-2010 20:17:50   

Basically I would like to use predicate builder to construct a FieldCompareRangePredicate.

Is this supported?

This is the code that I would like to write...


System.Linq.Expressions.Expression<Func<WorkOrderEntity, bool>> predicate = PredicateBuilder.Null<WorkOrderEntity>();
            predicate = predicate.And(wo => wo.Project.ClientId == searchVo.OrganizationIds);

Where searchVo.OrganizationIds is of type long[].

This code does not compile saying that "Operator '==' cannot be applied to operands of type 'long' and 'long[]'"

I can replace the code above with the next snippet, but this only handles 1 item in the array, not all of them.


System.Linq.Expressions.Expression<Func<WorkOrderEntity, bool>> predicate = PredicateBuilder.Null<WorkOrderEntity>();
            predicate = predicate.And(wo => wo.Project.ClientId == searchVo.OrganizationIds[0]);

I suppose I could iterate through the array using following code (which ends in the same result)...


System.Linq.Expressions.Expression<Func<WorkOrderEntity, bool>> predicate = PredicateBuilder.Null<WorkOrderEntity>();
foreach (var clientId in searchVo.OrganizationIds)
{
    predicate = predicate.Or(wo => wo.Project.ClientId == clientId);
}

However isnt it preferred to have TSQL That uses predicates that say "where clientId IN (1,2,3)" vs "where clientId = 1 or clientId =2 or clientId = 3" ? Or does SQL Server convert the IN clause into multiple OR statements?

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 13-May-2010 21:12:22   

I'd imagine SQL optimizes them to the same thing. You could check this by examining the execution plans of two queries differing only by having "IN (x,y,z)" or "OR x Or y Or z" to see if they are the same.

Cheers

Matt

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 13-May-2010 22:15:37   

Thanks for the reply. I will have a look when I get a chance.

However, the original question still applies...

I would like to use predicate builder to construct a FieldCompareRangePredicate.

Is this supported OR do I need to iterate the array / list and build a bunch of smaller OR clauses?

Thanks again.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 14-May-2010 06:13:37   

Using "Contains" is the way to create RangePredicate in LINQ2LLBL. Try this:

// values to filter
List<string> countries = new List<string>() { "USA", "UK" };

// build the predicate
var predicate = PredicateBuilder.Null<CustomerEntity>();
predicate = predicate.And(c => countries.Contains(c.Country));

// fetch
LinqMetaData metaData = new LinqMetaData(adapter);
var q = (from c in metaData.Customer
             select c).Where(predicate);
David Elizondo | LLBLGen Support Team
Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 14-May-2010 19:12:52   

Thank you for your reply. The field that I am trying to construct the predicate on is of type long, and does not seem to support "Contains". Is there anyway other than "Contains" to construct a range predicate expression in lin2llbl?

Is this the expected behavior for the long / Int64 datatype? I beleive that it may be.

In anycase, this is the only code that works so far. Is there a more elegant solution?


ClientStatusConverter converter = new ClientStatusConverter();
var statusPredicate = PredicateBuilder.Null<WorkOrderEntity>();
if (searchVo.ClientOrderStatuses.Contains(ClientOrderStatus.OPEN))
{
    foreach (OrderStatus orderStatus in converter.GetOpenOrderStatuses())
    {
        Int64 statusId = Convert.ToInt64(orderStatus);
        statusPredicate = statusPredicate.Or(wo => wo.StatusId.Equals(statusId));
    }
}

if (searchVo.ClientOrderStatuses.Contains(ClientOrderStatus.COMPLETE))
{
    foreach (OrderStatus orderStatus in converter.GetCompleteOrderStatuses())
    {
        Int64 statusId = Convert.ToInt64(orderStatus);
        statusPredicate = statusPredicate.Or(wo => wo.StatusId.Equals(statusId));
    }
}

if (searchVo.ClientOrderStatuses.Contains(ClientOrderStatus.DISCREPANCIES))
{
    foreach (OrderStatus orderStatus in converter.GetDiscrepancyOrderStatuses())
    {
        Int64 statusId = Convert.ToInt64(orderStatus);
        statusPredicate = statusPredicate.Or(wo => wo.StatusId.Equals(statusId) 
            && wo.ReasonId.Equals(Convert.ToInt64(ReasonCode.DISCREP)));
    }
}

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 15-May-2010 05:58:19   

This Contains is member of List<T> so you can use it in a List<long> as well:

List<long> myIds = new List<long>() { 1,2,3,...};

predicate = predicate.And(x => myIds.Contains(x.ProductId) );

Hope helpful.

David Elizondo | LLBLGen Support Team