This question already has an answer here:
Conditional WHERE in LINQ
(1 answer)
Closed 9 years ago.
I need to write a conditional query in linq:
if field.val1 == 0:
var q = from field in cw.fields
select field
if field.val1 != 0 and field.val2 == 0:
var q = from field in cw.fields
where field.val1 == 1
select field
if field.val1 != 0 and field.val2 != 0:
var q = from field in cw.fields
where field.val1 == 1 and field.val2 == 1
select field
How can I do this?
Because your condition depends on the values your querying, you have to just extend your where clause with additional cases using ||:
var q = from field in cw.fields
where
(field.val1 == 0) ||
(field.val1 != 0 and field.val2 == 0 && field.val1 == 1) ||
(field.val1 != 0 and field.val2 != 0 && field.val1 == 1 and field.val2 == 1)
select field
#MarcinJuraszek's answer will work but let me give a different perspective.
First of all, ditch the sql style syntax. It gets in the way, obscures what is actually going on and is generally just a feel-good abstraction rather than one that will result in more communicative code. Let's rewrite things using lambda syntax
IEnumerable<string> getFields(SomeField field, YourDatabase cw) {
if(field.val1 == 0:)
return cw.fields.ToList();
if(field.val1 != 0 and field.val2 == 0)
return cw.fields.Where(f => f.val1 ==1).ToList();
if(field.val1 != 0 and field.val2 != 0)
return cw.fields.Where(f => f.val1 == 1 and f.val2 == 1).ToList();
}
note that the only way things differ is the lambda, and a lambda is an object, in this case, an Expression object! So you can use a very standard abstract factory pattern here
return cw.fields.Where(matchingCondition(field)).ToList();
//elsewhere...
Expression<Func<SomeField, bool>> matchingCondition(SomeField field) {
if(field.val1 == 0:) return f => true;
if(field.val1 != 0 and field.val2 == 0) return f => f.val1 == 1
if(field.val1 != 0 and field.val2 != 0) return f => f.val1 == 1 and f.val2 == 1;
throw new InvalidOperationException("No match to condition");
}
Related
I'm trying to do a conditional OrderBy but it's having no effect. The List outputs the same with default ordering.
I've tried both approaches suggested in this question Conditional "orderby" sort order in LINQ
var query = _context.Groups
.Where(gr => gr.Status != ((sbyte)ActiveStatus.DELETED)
&& gr.OrganisationId == user.OrganisationId
&& (search != null && gr.Name != null ? (gr.Name.Contains(search)) : true == true)
)
.Select(GroupReportModel.Projection);
if(!pager.Sort.HasValue || pager.Sort.Value == ((int)Sort.MODIFIED))
query.OrderByDescending(gr => gr.Created.Date);
if(pager.Sort.Value == ((int)Sort.NAME))
query.OrderByDescending(gr => gr.Name);
pager.TotalRecords = query.Count();
var list = query.Skip(pager.PageCount != null ? pager.PageCount.Value * (pager.Page.Value) : 0)
.Take(pager.PageCount != null ? pager.PageCount.Value : 0)
.ToList();
LINQ methods do not mutate the query object, they return a new one, you need to reassign it:
if(!pager.Sort.HasValue || pager.Sort.Value == ((int)Sort.MODIFIED))
query = query.OrderByDescending(gr => gr.Created.Date);
if(pager.Sort.Value == ((int)Sort.NAME))
query = query.OrderByDescending(gr => gr.Name);
....
I have 4 checkboxes and based on which ones the user clicks on, I need to produce the LINQ statement. As mentioned below in the comment section, if I select just one checkbox, it works fine. If I select multiple checkboxes, it returns 0 results.
The 4 checkboxes are 1) "Item1" 2) "Item2" 3) "Item3" 4) "Item4".
This is what I have far:
var entity = _w_ItemRepository.GetMany(p => p.ID == id);
/* If I select just one item it works fine. If I select multiple items get 0 result */
entity = entity.Where
(p => (p.ItemType == 1 || !item1)
&& (p.ItemType == 2 || !item2)
&& (p.ItemType == 2 || !item3)
&& (p.ItemType == 3 || !item4)
);
I suspect the &&s need to be ||s. Consider if both item1 and item2 are true then you're essentially saying:
.Where(p => p.ItemType == 1 && p.ItemType == 2)
When the intent is probably:
.Where(p => p.ItemType == 1 || p.ItemType == 2)
(It also looks like there's a typo, you specify ItemType == 2 twice.)
Try:
entity = entity.Where
(p => (p.ItemType == 1 || !item1)
|| (p.ItemType == 2 || !item2)
|| (p.ItemType == 3 || !item3)
|| (p.ItemType == 4 || !item4)
);
Or I think this may be more clear, adding each clause if itemX is true:
entity = entity.Where
(p => (item1 && p.ItemType == 1)
|| (item2 && p.ItemType == 2)
|| (item3 && p.ItemType == 3)
|| (item4 && p.ItemType == 4)
);
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 ?
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.
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
hi guys i was using Dynamic SQL for search queries where i used to attach WHERE & AND clause piece by piece and form a statement, i recently came to below alternate for this, and life was amazing
cool alternates of Dynamic WHERE-Clause
Select * From tblEmployees
where EmployeeName = Coalesce(#EmployeeName, EmployeeName) AND
Department = Coalesce(#Department, Department ) AND
Designation = Coalesce(#Designation, Designation) AND
JoiningDate >= Coalesce(#StartDate, JoiningDate) AND
JoiningDate <= Coalesce(#EndDate, JoiningDate) AND
Salary >= Coalesce(#Salary, Salary)
now the issue is since i implemented entity framework i need to achieve same with Linq queries. i have nullable Byte type and nullable boolean which i am currently unable to handle
just like Coalesce my stupid attempt was
&& (s.Floors == deal.Floors.HasValue ? null : s.Floors)
below code not matching any results
[HttpPost]
public ActionResult Results(Deal deal, bool exactMatch)
{
List<Deal> deals;
if (exactMatch)
{
deals = dataBase.Deals.Where(s =>
(s.OwnerName.Contains(deal.OwnerName) || s.OwnerName == null)
&& (s.Rooms == deal.Rooms || s.Rooms == null)
&& (s.BathRooms == deal.BathRooms || s.BathRooms == null)
&& (s.Floors == deal.Floors || s.Floors == null)
&& (s.Builtin == deal.Builtin || s.Builtin == null)
&& (s.Kitchens == deal.Kitchens || s.Kitchens == null)
&& (s.DoubleUnit == deal.DoubleUnit || s.DoubleUnit == null)
&& (s.Corner == deal.Corner || s.Corner == null)
&& (s.Remarks.Contains(deal.Remarks) || s.Remarks == null)
).ToList();
}
else
{
deals = dataBase.Deals.Where(s =>
(s.OwnerName.Contains(deal.OwnerName) || s.OwnerName == null)
|| (s.Rooms == deal.Rooms || s.Rooms == null)
|| (s.BathRooms == deal.BathRooms || s.BathRooms == null)
|| (s.Floors == deal.Floors || s.Floors == null)
|| (s.Builtin == deal.Builtin || s.Builtin == null)
|| (s.Kitchens == deal.Kitchens || s.Kitchens == null)
|| (s.DoubleUnit == deal.DoubleUnit || s.DoubleUnit == null)
|| (s.Corner == deal.Corner || s.Corner == null)
|| (s.Remarks.Contains(deal.Remarks) || s.Remarks == null)
).ToList();
}
return View(deals);
}
table has values like
id Bathroom Floors
1 1 2
2 1 4
3 2 6
4 3 1
i need results which has id 1 & 2
for instance in front end user want to only fill bathroom field with "1" and leave floor field empty
Not really the same. In your query your coalesce is on the parameter then taking the record value as the default if it is null. In your c# lambda you are checking if the parameter is the same as the table value and then checking if the table value is null but that omits the possibility of having a null value in the parameter.
Example
Sql
Department = Coalesce(#Department, Department )
would be
(s.Department == deal.Department || deal.Department == null)
not this which is what you have now
(s.Department == deal.Department || s.Department == null)
Edit
If you wanted to duplicate the COALESCE expression you have now you could write it this way although I am not sure if it would decrease efficiency / performance.
(s.Department == (deal.Department ?? s.Department))
You are testing whether the field in the table equals the 'deal' property or the field is null rather than doing this:
s.Remarks.Contains(deal.Remarks) || deal.Remarks == null
If you do this, it should be the equivalent query.
You can do this cumulatively too. For example with the exact match case you can do:
deals = dataBase.Deals;
if (deal.OwnerName != null)
deals = deals.Where(s => s.OwnerName.Contains(deal.OwnerName));
if (deal.Rooms != null)
deals = deals.Where(s => s.Rooms == deal.Rooms)
That can make the resulting query more efficient. There's a similar way to do this with the non exact match through using unions. I don't know the syntax off hand.
This question already has answers here:
Only do Where condition if a value is passed in
(4 answers)
Closed 9 years ago.
public List<..> GetSomething(int column1Value, int column2Value, string column3Value)
{
from t1 in this.DataContext.Table1
where t1.column1 == column1Value &&
t1.column2 == column2Value &&
t1.column3 == column3Value
}
Now I want to re-use the above query i.e. don't want to duplicate it, but the ONLY difference is I want the t1.column3 == column3Value to be option so I call this like:
GetSomething(1,2,"HELLO");
and
GetSomething(1,2);
Is it possible to make this part of the where clause conditional? Meaning if you pass in "", then it ignores that clause?
Yes, just break your statement into two parts like this:
var query = this.DataContext.Table1
.Where( x => column1 == column1Value && x.column2 == column2Value);
if ( column3Value != "" )
query = query.Where( x => x.column3 == column3Value);
// Your existing processing of query
Try this:
public List<..> GetSomething(int column1Value, int column2Value, string column3Value = null) {
from t1 in this.DataContext.Table1
where t1.column1 == column1Value &&
t1.column2 == column2Value &&
(column3Value == null ? true : t1.column3 == column3Value)
}
I suggest ou to define OR operator in order to define such as optional
Make the parameter optional, and test for the lack of it:
public List<..> GetSomething(int column1Value, int column2Value,
string column3Value = null)
{
from t1 in this.DataContext.Table1
where t1.column1 == column1Value &&
t1.column2 == column2Value &&
(column3Value == null || t1.column3 == column3Value)
}