I have the following code:
decimal? sumFreightAmount = (db.Trips
.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year)
.Sum(p => p.FreightAmount));
if (sumFreightAmount.HasValue)
{
// my actions
}
else
{
sumFreightAmount = 0;
}
I can write it the following way:
decimal sumFreightAmount = (
db.Trips
.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year)
.Sum(p => p.FreightAmount) != null)
?
(db.Trips
.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year)
.Sum(p => p.FreightAmount)) : 0;
but in this place I call linq extension twice (and have a long record). I have read, that I can write more shorter it in the latest version of C#, like
decimal sumFreightAmount = (db.Trips.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year).Sum(p => p.FreightAmount)?.0;
but can't find it. What is the shortest record?
The best way is using GetValueOrDefault
decimal sumFreightAmount = db.Trips
.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year)
.Sum(p => p.FreightAmount)
.GetValueOrDefault();
EDIT: As #IvanStoev pointed out, you can also use the null coalescing operator in this case, which is a tad bit shorter:
decimal sumFreightAmount = db.Trips
.Where(p => p.DateTime.Month == i && p.DateTime.Year == DateTime.Now.Year)
.Sum(p => p.FreightAmount) ?? 0;
Related
I created where conditions with linq lambda expression for reporting. My conditions are running very slowly or it is throwing error.
Error Detail: Evoluation timed out.
How can i find correct query?
My codes:
var query = Worker.Members
.Where(u => string.IsNullOrEmpty(model.TcNumber) || u.TcNumber.Contains(model.TcNumber))
.Where(u => string.IsNullOrEmpty(model.FullName) || u.FullName.Contains(model.FullName))
.Where(u => model.BirthYear == null || u.BirthDate.Year >= model.BirthYear)
.Where(u => model.BirthYearLevel == null || u.BirthDate.Year <= model.BirthYearLevel)
.Where(u => model.BirthYearLevel == null || u.BirthDate.Year <= model.BirthYearLevel)
.Where(u => model.GenderId == null || u.GenderId == model.GenderId)
.Where(u => model.DistrictCode == null || u.Contacts.Any(c => c.DistrictCode == model.DistrictCode && c.IsActive))
.Where(u => model.StreetCode == null || u.Contacts.Any(c => c.StreetCode == model.StreetCode && c.IsActive))
.Where(u => model.ExteriorDoor == null || u.Contacts.Any(c => c.ExteriorDoor == model.ExteriorDoor && c.IsActive))
.Where(u => model.InteriorDoor == null || u.Contacts.Any(c => c.InteriorDoor == model.InteriorDoor && c.IsActive))
.Where(u => model.DisabledGroupId == null || u.Disableds.Any(d => d.ReportDisabledGroups.Any(c => c.DisabledGroupId == model.DisabledGroupId)))
.Where(u => model.ContributionTypeId == null || u.Demands.Any(d => d.ContributionTypeId == model.ContributionTypeId && !d.IsDeleted))
.Where(u => model.DemandStatusId == null || u.Demands.Any(d => d.DemandStatusId == model.DemandStatusId && !d.IsDeleted))
.Where(u => model.DemandDateStart == null || u.Demands.Any(d => d.DemandDate >= model.DemandDateStart && !d.IsDeleted))
.Where(u => model.DemandDateEnd == null || u.Demands.Any(d => d.DemandDate <= model.DemandDateEnd && !d.IsDeleted))
.Where(u => u.IsTcCitizen == model.IsForeign)
.Where(u => u.IsDisabled == model.IsDisabled)
.Where(u => u.IsAlive == model.IsAlive);
The correct pattern (assuming Worker.Members is an IQueryable, not an IEnumerable) here is to conditionally add the criteria, like this:
var query = Worker.Members;
if (!string.IsNullOrEmpty(model.TcNumber))
query = query.Where(u => u.TcNumber.Contains(model.TcNumber));
if (!string.IsNullOrEmpty(model.FullName)
query = query.Where(u => u.FullName.Contains(model.FullName));
if (!model.BirthYear == null)
query = query.Where(u => u.BirthDate.Year >= model.BirthYear);
. . .
Did you check this?
Here detailed descriptions are given.
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()
This is my method:
public IEnumerable<Web_Vendor> GetSaleBrands()
{
using (var _db = new LuxedecorContext())
{
IQueryable<Web_Vendor> web_vendors = _db.Web_Vendor.
Where(x =>
(_db.Web_Promotion.Where(z => z.VendorID != string.Empty
&& z.Static == true && z.Percent != 0 &&
(x.WebPromotion.Expires >= DateTime.Now || x.WebPromotion.Expires == null))
.Select(r => r.VendorID).Contains(x.VendorID))
||
(_db.NavItems.Where(y => x.WebPromotion.VendorID == y.SC1
&& !(y.Promotion == "" || y.Promotion == null)
&& (y.PromotionStart <= DateTime.Now) && (y.PromotionEnd >= DateTime.Now || y.PromotionEnd == null))
.Select(g => g.SC1).Contains(x.WebPromotion.VendorID)))
.Where(x => x.Active == true).OrderBy(x => x.NameExtra)
.ThenBy(x => x.Sequence);
var a = web_vendors.ToList(); // 16 values
var b = web_vendors.Include(x => x.WebPromotion).ToList(); // 13 values
}
throw new NotImplementedException();
}
I need to Include nullable values to my collection of Web_Vendors. I know, it's famous question, but I need to return collection of Web_Vendors instead of collection of dynamic types. Is it possible?
I need to write a/multiple LINQ queries to get some data that I will display for a report.
The tables I need to use are StaffingResources, StaffingForecastEvents (which link a StaffingResource to a Project), and StaffingForecasts (which link to StaffingForecastEvents and contain hours for each week). Each StaffingResource can have 0-many StaffingForecastEvents, and a StaffingForecastEvent can have 0-many StaffingForecasts.
I need to write LINQ query that, for each Resource, will contain all of the projects they have ForecastEvents on, and for each Project all of their Forecasts for a given date range (which is either a 12 weeks or 6 months). Here is what I have so far, and it is running pretty slow.
// Get date ranges
var dates = new List<DateTime>();
var startDate = range == (int)RangeTypes.WEEKLY
? DateTime.Today.AddDays(DayOfWeek.Monday - DateTime.Today.DayOfWeek)
: new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
for (var i = 0; i < (range == (int)RangeTypes.WEEKLY ? 4 : 6); i++)
{
dates.Add(range == (int)RangeTypes.WEEKLY ? startDate.AddDays(i * 7) : startDate.AddMonths(i));
}
var endDate = dates[dates.Count-1];
// Get resources
var resources = from r in context.StaffingResourceDatas
where r.EmployeeId.HasValue
&& (resourceIds.Count == 0 || resourceIds.Contains(r.EmployeeId.Value))
&& (resourceDivisions.Count == 0 || resourceDivisions.Contains(r.ResourceDivisionId))
&& (resourceTitles.Count == 0 || resourceTitles.Contains(r.ResourceTitleId))
&& (resourceLocations.Count == 0 || resourceLocations.Contains(r.ResourceLocationId))
&& (supervisors.Count == 0 || supervisors.Contains(r.ReportsToId))
&& (showAllResources || (!showAllResources && !exclusionList.Contains(r.ResourceTitleId)))
join fe in context.StaffingForecastEvents
.Include(x => x.StaffingForecasts)
.Include(x => x.StaffingUser)
.Include(x => x.StaffingUser1)
.Include(x => x.StaffingForecasts.Select(y => y.StaffingUser))
.Include(x => x.StaffingForecasts.Select(y => y.StaffingUser1))
on r.ResourceId equals fe.ResourceId into g1
from fe in g1.DefaultIfEmpty()
join p in context.StaffingProjectDatas on fe.JobNumber equals p.JobNumber into g2
from p in g2.DefaultIfEmpty()
group new { ForecastEvent = fe, Project = p } by r into g3
select new
{
ResourceId = g3.Key.ResourceId,
Name = g3.Key.ResourceName,
Title = g3.Key.ResourceTitle,
Division = g3.Key.ResourceDivision,
Location = g3.Key.ResourceLocation,
AvailableDate = g3.Key.AvailableDate,
SupervisorEmail = g3.Key.ManagerEmail,
Projects = g3.Where(p => p.ForecastEvent != null).Select(p => new
{
JobNumber = p.ForecastEvent.JobNumber,
Description = p.Project.ProjectDescription,
Name = p.Project.ProjectName,
Division = p.Project.ProjectDivision,
ProjectManager = p.Project.PMName,
Notes = p.ForecastEvent.Notes,
LogDate = p.ForecastEvent.LogDate,
LogUser = p.ForecastEvent.StaffingUser.Name,
AckDate = p.ForecastEvent.AcknowledgeDate,
AckUser = p.ForecastEvent.StaffingUser1 != null ? p.ForecastEvent.StaffingUser1.Name : null,
Usages = dates.Select(d => new
{
Date = d,
Hours = (range == (int)RangeTypes.WEEKLY)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any() ? p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Sum(f => f.Hours) : 0)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any() ? p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Sum(f => f.Hours) : 0),
LogDate = (range == (int)RangeTypes.WEEKLY)
// Get acknowledge or log date for week
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any()
? ((p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate)
: (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).LogDate)
: null)
// Get acknowledge or log date for most recent forecast for month
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any()
? ((p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Max(f => f.LogDate))
: null),
LogUser = (range == (int)RangeTypes.WEEKLY)
// Get acknowledge or log user for week
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any()
? ((p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).StaffingUser1.Name)
: (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).StaffingUser.Name)
: null)
// Get acknowledge or log user for most recent forecast for month
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any()
? ((p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().StaffingUser1.Name)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().StaffingUser.Name)
: null),
})
})
};
I will also need to get totals for each resource for each date range.
I feel like the bottleneck is probably with all the "Where"s when looping through the dates, but I don't know what else to do. Any ideas?
As a starting point you can split it up into several expressions using IQueryable<T>. It would also help you make your where clauses simpler. That would look something like:
var queryable = context.StaffingResourceDatas.Where(r => r.EmployeeId.HasValue);
if(resourceIds.Any())
{
queryable = queryable.Where(r => resourceIds.Contains(r.EmployeeId.Value))
}
Notice that this will generate SQL related to filtering by resourceIds only if resourceIds is not empty, thus potentially saving the overhead of checking it in the generated query itself.
You can write the rest of the filters similarly to this one. Also notice that query won't get executed until you call ToList() on it. So you can keep adding as many clauses as you like, until you're done constructing it.
But at the end of the day you might want to consider writing this one in raw SQL because it's just, you know, gigantic.
I have those statements who checks if I have all the answers in a Grid. Each row is identified by a ContextYID.
I would like to know if i can combine those LinQ query and convert it directly to a True/False Statement.
int nbRow = Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count();
int nbAnswer = Answers.Count(a =>
a.FieldId == result.Id &&
a.FieldXId == fieldXAxi.Id &&
a.FieldYId == fieldYAxi.Id);
if (nbAnswer != nbRow)
return false;
else
return true;
I think this is an improvement, because the FieldId and FieldYID only need to be compared once, and I simplified your return statements into one line.
var matchingAnswers = Answers.Where(a => a.FieldId == result.Id
&& a.FieldYId == fieldYAxi.Id).ToList();
int nbRow = matchingAnswers
.Select(a => a.ContextYId)
.Distinct()
.Count();
int nbAnswer = matchingAnswers.Count(a => a.FieldXId == fieldXAxi.Id);
return nbAnswer == nbRow;
If you like, you can shorten this by merging the last few lines:
var matchingAnswers = Answers.Where(a => a.FieldId == result.Id
&& a.FieldYId == fieldYAxi.Id).ToList();
return matchingAnswers.Count(a => a.FieldXId == fieldXAxi.Id) ==
matchingAnswers.Select(a => a.ContextYId).Distinct().Count();
Wouldn't equals work?
return Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count()
.Equals(Answers.Count(a =>
a.FieldId == result.Id &&
a.FieldXId == fieldXAxi.Id &&
a.FieldYId == fieldYAxi.Id));
I think this should work. Is there a particular reason you want to do this?
return Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Select(a => a.ContextYId)
.Distinct()
.Count()
== Answers.Count(a => a.FieldId == result.Id
&& a.FieldXId == fieldXAxi.Id
&& a.FieldYId == fieldYAxi.Id)
I think this is functionally equivalent to what are doing (but I do wonder what you're doing for the duplicate ContextYIds that satisfy nbAnswer multiple times):
var distinctContextYIds = new HashSet<int>();
return 0 == Answers.Where(a => a.FieldId == result.Id && a.FieldYId == fieldYAxi.Id)
.Aggregate(0, (tally, answer) =>
{
if (distinctContextYIds.Add(answer.ContextYId))
tally += 1;
if (answer.FieldXId == fieldXAxi.Id)
tally -= 1;
return tally;
});