wrong expression result linq - c#

I want to get records with parentIds. But this Linq expression gave me elements with 0 parentId value.
var orders =
OrderEquityTransactions.AsParallel().Where(
o => o.FinancialInstrumentId == financialInstrumentPrice.FinancialInstrumentId &&
o.ParentId != 0 &&
o.DebitCredit == "A" ? o.Price >= financialInstrumentPrice.Price : o.Price <= financialInstrumentPrice.Price).ToList();
After some digging I rewrote expression with additional two brackets and problem solved.
var orders =
OrderEquityTransactions.AsParallel().Where(
o => o.FinancialInstrumentId == financialInstrumentPrice.FinancialInstrumentId &&
o.ParentId != 0 &&
(o.DebitCredit == "A" ? o.Price >= financialInstrumentPrice.Price : o.Price <= financialInstrumentPrice.Price)).ToList();
What is the reason of this behavior?

Because in the first case it was interpreted as:
o => (o.FinancialInstrumentId == financialInstrumentPrice.FinancialInstrumentId
&& o.ParentId != 0 && o.DebitCredit == "A")
? o.Price >= financialInstrumentPrice.Price
: o.Price <= financialInstrumentPrice.Price
which is absolutely another.
Please, read this article on operator precedence.
Ternary conditional operator has the lower priority than conditional AND.

As per Operator precedence and associativity, conditional ANDs have a higher precedence than the conditional operator. So C# evaluates your expresion like this:
(o.FinancialInstrumentId == financialInstrumentPrice.FinancialInstrumentId
&& o.ParentId != 0 && o.DebitCredit == "A")
? o.Price >= financialInstrumentPrice.Price
: o.Price <= financialInstrumentPrice.Price

Related

LINQ Conditional OrderBy

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);
....

limiting by an additional LINQ parameter

I have the following in an MVC application:
var selectedArticles =
vm.Articles.Except(
vm.Articles.Where(x => x.Quantity == 0)).ToList();
I need to add another parameter. I DONT want to show the articles where the option HideUntilDate != NULL && HideUntilDate > todays date
Any tips?
Except not needed
var selectedArticles = vm.Articles
.Where(a => a.Quantity == 0 && !(a.HideUntilDate != null && a.HideUntilDate.Value > DateTime.Today));
Just add the requirement logic to your where clause's lambda expression
var selectedArticles =
vm.Articles.Except(
vm.Articles.Where(
x => x.Quantity == 0 ||
x.HideUntilDate == null ||
x.HideUntilDate < DateTime.Now.Date()
)
).ToList();

Not understanding LINQ query

I am maintaining a project and have come across some code which I can't understand. LINQ query:
var toDraw = from tile in testArr.AsEnumerable()
where tile.Item_Business_Unit != null ?
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0)) :
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0))
select tile;
From what I understand, from an array a tile is being selected which has the following criteria:
Ending date can be datetime.now or datetime.minvalue
Sales code can be null or can be equal to customer no or cpg
Unit price should be greater than 0
But I am not understanding why there is a conditional expression after tile.Item_Business_Unit since both of the conditions perform the same thing. So will the item be selected even if it has a null business unit? And does this work different from normal if/else operations?
Any suggestions would be very appreciated.
Are you being thrown by the shortcut notation?
x = (test_case) ? (true_part) : (false_part);
If test_case evaluates to true, you would have
Whereas if test_case evaluates to false, this expression would be evaluated
UPDATE:
As an FYI: The resulting test of both sides of that conditional expression above are equal, so that cryptic code is not even necessary.
You could replace that with this:
var toDraw = from tile in testArr.AsEnumerable()
where
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) || (tile.Sales_Code.ToString() == cpg)) &&
(tile.Unit_Price != 0))
select tile;

Is there a better way of shortening this LINQ statement?

var filteredItemNumber = 0;
if (!string.IsNullOrEmpty(searchTerm))
{
filteredItemNumber =
this._objectsRep.Find(
r =>
r.ObjectTitle.StartsWith(searchTerm) && r.CreatedDate >= timePeriod.Start
&& r.CreatedDate <= timePeriod.End).Count();
}
else
{
filteredItemNumber =
this._objectsRep.Find(t => t.CreatedDate >= timePeriod.Start && t.CreatedDate <= timePeriod.End)
.Count();
}
I am sure there must be a shorten way to get rid of the if statement but I cannot figure it out how. when I use the following code the filtering returns different result than what I am expecting. Maybe the parentheses are not in right place ?
this._objectsRep.Find(r =>
searchTerm == null || r.ObjectTitle.StartsWith(searchTerm) && r.CreatedDate >= timePeriod.Start
&& r.CreatedDate <= timePeriod.End).Count()
What I am trying to achieve is that if the serchTerm is empty or null just ignore that filter but use the date range only.
Thanks
You don't need List.Find which returns a new list, you can use LINQ to count:
int filteredItemNumber = _objectsRep.Count(r =>
(string.IsNullOrEmpty(searchTerm) || r.ObjectTitle.StartsWith(searchTerm))
&& r.CreatedDate >= timePeriod.Start
&& r.CreatedDate <= timePeriod.End);
I think you just need to wrap the searchTerm condition like this:
this._objectsRep.Find(r =>
(string.IsNullOrEmpty(searchTerm) || r.ObjectTitle.StartsWith(searchTerm))
&& r.CreatedDate >= timePeriod.Start
&& r.CreatedDate <= timePeriod.End).Count()
filteredItemNumber =
this._objectsRep.Find(
r =>
r.ObjectTitle.StartsWith(searchTerm??"") && r.CreatedDate >= timePeriod.Start
&& r.CreatedDate <= timePeriod.End).Count();

Entity framework strings using greater than operator

How do I make this query work like it does in sql? In sql I can use < and > operators on strings.
I've been googling this for about 20 minutes and have found no solution yet.
I cannot convert r.ExemptionCode to an integer as it may have values like '91A,9AA,ZZZ,Z01'
from r in results
where (r.ExemptionCode > "900" || r.ExemptionCode == "701" || r.ExemptionCode == "702" || r.ExemptionCode == "721" || r.ExemptionCode == "724")
select r
Try this :
from r in results
where (r.ExemptionCode.CompareTo("900") > 0 || r.ExemptionCode == "701" || r.ExemptionCode == "702" || r.ExemptionCode == "721" || r.ExemptionCode == "724")
select r

Categories

Resources