I have this linq query that works well (although it may be written better, pls say so if you notice something)
var qry = BenefitCodes
.Where(b => b.BenInterest != 'E'
&& (b.BenProductLine == CoverageProductLine || b.BenProductLine == null) )
.Select(b => b)
.OrderBy(b => b.BenDesc);
A new requirement came down the pipeline to exclude two BenCodes ( 1001, 1009), BenCodes is just another column in the SQL table.
Am I supposed to use some variation of ".Contains", I would have to do !Contains or something. Can anyone point me in the right direction?
Thanks,
~ck in San Diego
Yes, one way to handle this is the following (for brevity and readability, I am excluding the remainder of your query):
var excludedBenCodes = new List<int>() { 1001, 1009 };
var query = BenefitCodes.Where(b => !excludedBenCodes.Contains(b.BenCodes));
I believe this to be more readable and more maintainable than the alternative of adding a subclause b.BenCodes != 1001 && b.BenCodes != 1009 to your where clause.
You could just simply add another line to the Where clause and exclude every itm with a BenCodes of 1001 or 1009.
Like this:
var qry =
BenefitCodes
.Where(b =>
b.BenInterest != 'E' &&
(b.BenProductLine == CoverageProductLine || b.BenProductLine == null) &&
b.BenCodes != 1001 &&
b.BenCodes != 1009)
.Select(b => b)
.OrderBy(b => b.BenDesc);
This might make things a bit more readable, I'd change query to
var qry = BenefitCodes.Where(b => FitsCriteria(b)).OrderBy(b => b.BenDesc);
and add method
public bool FitsCriteria(BenefitCode b)
{
return b.BenInterest != 'E' &&
(b.BenProductLine == CoverageProductLine || b.BenProductLine == null) &&
b.BenCodes != 1001 &&
b.BenCodes != 1009;
}
Kindness,
Dan
var qry = BenefitCodes
.Where(b => b.Code != '1001'
&& b.Code != '1009'
&& b.BenInterest != 'E'
&& ( b.BenProductLine == CoverageProductLine
|| b.BenProductLine == null))
.OrderBy(b => b.BenDesc);
You don't even need the "Select" when you aren't using the LINQ syntax. as the Where and OrderBy methods already return your IQueryable.
Related
I have two queries, the first returns all "Open" records where the reply-by-date has not passed and the second returns all "Open Unviewed" records where the reply-by-date has not passed and the record has not been viewed by the user (no entry in table RfqVieweds). In this scenario the user has not viewed any of the 1000 records so all 1000 are returned. The second to last line in each query (right before "select new RfqDto()") is where the difference is between the two queries.
The first query takes about 45 seconds to return 1000 records. The second query takes about 4 seconds to return the same 1000 records. Why? How do I get the first query to run as fast as the second?
Query 1:
var groupQuery = Rfqs.Where(rfqs => rfqs.IsPrimaryEmail && (rfqs.Contract != "Upstream"))
.GroupBy(rfqs => new {rfqs.RFQ_RFISeqNum})
.Select(g => new {g.Key.RFQ_RFISeqNum, RfqId = g.Max(p => p.RfqId)});
var query = (from m in groupQuery
join t in Rfqs on new {m.RfqId} equals new {t.RfqId}
join s in RfqSupplementals on new {RfqSeqNumber = t.RFQ_RFISeqNum} equals new {s.RfqSeqNumber}
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
from rfqStarred in RfqUserStarreds.Where(rs => rs.RfqSeqNumber == t.RFQ_RFISeqNum && rs.SalesRep == salesrep).DefaultIfEmpty()
let rcn = RfqCommentNotifications.Where(r => r.RfqSequenceNum == t.RFQ_RFISeqNum && r.SalesRep == salesrep).Select(d => d.LastViewed).FirstOrDefault()
let ch = RfqsChangeHistories.Where(r => r.RfqRfiSeqNum == t.RFQ_RFISeqNum && chgHistList.Contains(r.Action)).OrderByDescending(r => r.Id).FirstOrDefault()
where (isRfqUser == false || ((t.assignedTo == salesrep || t.secndAssignedTo == salesrep || t.addlAssignedTo == salesrep)
|| (agencies.Contains(t.Agency) && (t.assignedTo == null || t.assignedTo.Trim() == string.Empty)
&& (t.secndAssignedTo == null || t.secndAssignedTo.Trim() == string.Empty) && (t.addlAssignedTo == null || t.addlAssignedTo.Trim() == string.Empty))))
&& (!isRfqUser || t.HouseOpportunity == false)
&& t.IsDeleted == false && t.IsPrimaryEmail
&& (t.ReplyByDate > now || (t.ReplyByDate == null && t.IsManualRfq))
select new RfqDto()
Query 2:
var groupQuery = Rfqs.Where(rfqs => rfqs.IsPrimaryEmail && (rfqs.Contract != "Upstream"))
.GroupBy(rfqs => new {rfqs.RFQ_RFISeqNum})
.Select(g => new {g.Key.RFQ_RFISeqNum, RfqId = g.Max(p => p.RfqId)});
var query = (from m in groupQuery
join t in Rfqs on new {m.RfqId} equals new {t.RfqId}
join s in RfqSupplementals on new {RfqSeqNumber = t.RFQ_RFISeqNum} equals new {s.RfqSeqNumber}
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
from rfqStarred in RfqUserStarreds.Where(rs => rs.RfqSeqNumber == t.RFQ_RFISeqNum && rs.SalesRep == salesrep).DefaultIfEmpty()
let rcn = RfqCommentNotifications.Where(r => r.RfqSequenceNum == t.RFQ_RFISeqNum && r.SalesRep == salesrep).Select(d => d.LastViewed).FirstOrDefault()
let ch = RfqsChangeHistories.Where(r => r.RfqRfiSeqNum == t.RFQ_RFISeqNum && chgHistList.Contains(r.Action)).OrderByDescending(r => r.Id).FirstOrDefault()
where (isRfqUser == false || ((t.assignedTo == salesrep || t.secndAssignedTo == salesrep || t.addlAssignedTo == salesrep)
|| (agencies.Contains(t.Agency) && (t.assignedTo == null || t.assignedTo.Trim() == string.Empty)
&& (t.secndAssignedTo == null || t.secndAssignedTo.Trim() == string.Empty) && (t.addlAssignedTo == null || t.addlAssignedTo.Trim() == string.Empty))))
&& (!isRfqUser || t.HouseOpportunity == false)
&& t.IsDeleted == false && t.IsPrimaryEmail
&& (rfqViewed == null && (t.ReplyByDate > now || (t.ReplyByDate == null && t.IsManualRfq)))
select new RfqDto()
You probably need to look at the query plan to see the true reason for the timing difference, as it depends on the actual data.
The two queries are different and if they happen to return the same number of rows, then Sql will have no way of knowing that in advance.
I can give you an example of one circumstance which could cause the difference.
First of all, lets simplify the query to
var query = (from m in groupQuery
join t in Rfqs on new { m.RfqId } equals new { t.RfqId }
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
where
t.ReplyByDate > now
select new RfqDto()
Now suppose you have 1 million rows in Rfqs and only 1000 records have a ReplyByDate values in the future. If ReplyByDate is not indexed, then that means that sql has to read and check all million rows before returning the selected 1000 rows.
But if the query becomes
var query = (from m in groupQuery
join t in Rfqs on new { m.RfqId } equals new { t.RfqId }
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
where
(t.ReplyByDate > now
&& rfqViewed == null
select new RfqDto()
and if it happens that there are only 10000 rows in Rfqs that do not have a record in RfqVieweds, and if rfqViewed has a suitable index that Sql can determine this quickly, then that means that Sql will only need to look at these 10000 records, which may be faster.
Note, If there are any rows with ReplyDates in the future that have been reviewed, then the two queries will not return the same records.
My requirement is to make boolean value (IsPC=true) only if I found any value with IsCurrent = true from the list and second condition is to filter the list with G or W codes and third condition is to check the PCBNumber length ==15 with only one from the list.
How short can i able to reduce the below query using LINQ method syntax
below is my query
var CurrentQ= p.List.Where(x => x.IsConCurrent== true);
if (CurrentQ.Count() > 0)
{
var NCurrentQwithWorQ = p.List.Where(x => x.Codes == Codes.W|| x.Codes== Codes.Q).Count();
if (NCurrentQwithWorQ != null)
{
var PCBNumber = p.List.Where(x => x.PCBNumber .Length == 15).Count();
if (PCBNumber == 1)
{
isPC = true;
}
}
}
You can use all conditions in same query like below,
var PCBNumber= p.List.Where(x => x.IsConCurrent== true && (x.Codes == Codes.W|| x.Codes== Codes.Q) && x.PCBNumber.Length == 15);
if (PCBNumber !=null && PCBNumber.Count() == 1)
{
isPC = true;
}
I'm not trying to debug what you wrote, but isn't this really what you're looking for--that is, daisy-chaining your Where conditions?
var isPC = p.List.Where(x => x.IsConCurrent == true).Where(x => x.Codes == Codes.W || x.Codes == Codes.Q).Where(x => x.PCBNumber.Length == 15).Count() == 1;
Both solutions suggested above are correct.
p.List.Where(x => x.IsConCurrent== true && (x.Codes == Codes.W|| x.Codes== Codes.Q) && x.PCBNumber.Length == 15);
p.List.Where(x => x.IsConCurrent == true).Where(x => x.Codes == Codes.W || x.Codes == Codes.Q).Where(x => x.PCBNumber.Length == 15).Count()
Actually they are performed in the same way. The Where function does not force immediate iteration through the data source. Only when you execute the Count function, LINQ will process row by row and execute criterion by criterion to find out which values should be calculated.
I can only suggest you add the Take(2) operator after the where clause. In this case LINQ will stop after finding the first two rows that matches provided criterion and other rows will not be processed.
p.List.Where(x => x.IsConCurrent == true)
.Where(x => x.Codes == Codes.W || x.Codes == Codes.Q)
.Where(x => x.PCBNumber.Length == 15)
.Take(2).Count()
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();
I am trying to get the result based upon the values of variables temp_DestinationGroupName, temp_CountryName and temp_RateTypeId.
If any of these variables are null or 0, it should not be included in where clause and rest statements should work and bring the result. I am getting zero rows using this query. Kindly suggest me something with these conditions in where clause. i tried following solutions on stackoverflow but still not getting the desired result.
var Rows = _CustomerRatesList.Where(w => (w.Id != rates.Id)
&& (w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName!= null)
&& (w.CountryName == temp_CountryName || temp_CountryName!=null)
&& (w.RateTypeId == temp_RateTypeId || temp_RateTypeId !=0));
(w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName!= null)
Your condition here will return true as long as your input variable temp_DestinationGroupName is not null. I don't think that's what you had in mind.
You can split in many Where to make your request more readable :
var Rows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName != temp_DestinationGroupName || temp_DestinationGroupName != null)
.Where(w => w.CountryName != temp_CountryName || temp_CountryName != null)
.Where(w => w.RateTypeId != temp_RateTypeId || temp_RateTypeId !=0);
Notice that you must use != in first conditioon of all Where, so you'll get all data except when it's null. In your logic, may be the conditions will be == :
var Rows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName == null)
.Where(w => w.CountryName == temp_CountryName || temp_CountryName == null)
.Where(w => w.RateTypeId == temp_RateTypeId || temp_RateTypeId ==0);
Each Where result is an IEnumerable, Rows will be a IEnumerable. If you want a List, just add .ToList()
I got the solution to this problem, now i am getting filtered result.
Thank you all for your time :)
var otherRows = _CustomerRatesList.Where(w => w.Id != rates.Id)
.Where(w => w.DestinationGroupName == temp_DestinationGroupName || temp_DestinationGroupName == null)
.Where(w => w.CountryName == temp_CountryName || temp_CountryName == null)
.Where(w => w.RateTypeId == temp_RateTypeId || temp_RateTypeId == 0);
Hi any suggestions on building a LINQ statement based on search criteria?
I'll be passing in an instance of a 'SearchCriteria' class with all parameters nullable.
I then want to
if (sc.a != null)
// add to where
if (sc.b != null)
// add to where
The key thing is these are to be ORs not ANDs.
Any tips?
And for bonus points I'd like to use 'contains' on an int? but I can only get equals or not equals.
Try:
.Where(x =>
(x.a != null ? x.a == a : false) &&
(x.b != null ? x.b == b : false));
or
.Where(x =>
(x.a != null && x.a == a) ||
(x.b != null && x.b == b));
Also:
.Where(x => new int[] { 1, 2, 3 }.Contains(x.i));