kwv84
kwv84

Reputation: 953

Add conditional OR clause to LINQ query

I have an MVC5 project. On my page I have 4 checkboxes and a search button. When the button is clicked, an ajax call is triggered to call the function below:

[HttpPost]
public ActionResult GetOpenOrders(ProductionStatus pStatus)
{
    List<vw_orders> orderList = new List<vw_orders>();

    OrderRepository orderRepo = new OrderRepository();

    // Get the total list of open orders
    orderList = orderRepo.getAllByStatus("V");

    // If not all values are 0, we have to filter
    // (allZero is a private function that checks if all property values of pStatus are 0)
    if(allZero(productieStatus) != true)
    {
        // Only use the properties of pStatus where
        // the value is 1
        // example: pStatus.A = 1, pStatus.B = 0, pStatus.C = 1
        orderList = orderList.Where( p => if(pStatus.A == 1) p.a == pStatus.A || if(pStatus.B == 1) p.b == pStatus.B || if(pStatus.C == 1) p.c = pStatus.C);

    }

    // return some json of orderList.ToList()
}  

How can I add the OR condition conditionally to my WHERE clause, thus only when value of pStatus.property == 1 ?

Upvotes: 1

Views: 954

Answers (2)

fubo
fubo

Reputation: 45947

replace

orderList = orderList.Where(p => if(pStatus.A == 1) p.a == pStatus.A || if(pStatus.B == 1) p.b == pStatus.B || if(pStatus.C == 1) p.c = pStatus.C)

with

orderList = orderList.Where(p => (pStatus.A == 1 && p.a == pStatus.A) ||
                                 (pStatus.B == 1 && p.b == pStatus.B) || 
                                 (pStatus.C == 1 && p.c == pStatus.C))

thus only when value of pStatus.property == 1

so p.a == pStatus.A and for pStatus.A == 1 need to be true to make this row part of the result.

Upvotes: 3

Lithium
Lithium

Reputation: 393

If I understand your question correctly, you want to check the value of a property iff the respective property is set in the pStatus object.

This is simply, if pStatus.A == 1 then p.A == pStatus.A must be true. The problem with this statement is that we have to check the first part pStatus.A == 1, and then determine if we need to check the second part p.A == pStatus.A; which, we want to avoid having too many conditional checks within our linq statement since things can quickly get messy. So let's try to reduce what you are really checking for.

An easy way to show this is statement is as X=>Z(if X then Z), where X = pStatus.A == 1 and Z = p.A == pStatus.A. X=>Z is logically equivalent to ¬X v Z (not X or Z), because if X is not true we don't care what Z is and if Z is true then we don't care if X is true. In your situation, if pStatus.A != 1 then it doesn't matter what p.A is equal to, and if p.A == pStatus.A then it doesn't matter if pStatus.A == 1 or not because in either case the check will pass.

Now, if we substitute back in your checks for X and Z we get (!(pStatus.A == 1) || p.A == pStatus.A) which we can move the not inside the parenthesis and get (pStatus.A != 1 || p.A == pStatus.A).

If we substitute this equivilant statement in for the checks we get:

orderList = orderList.Where( p => (pStatus.A != 1 || p.A == pStatus.A) && (pStatus.B != 1 || p.B == pStatus.B) && (pStatus.C != 1 || p.C == pStatus.C);

We use && between the groups because we want each check to have to pass

Upvotes: 0

Related Questions