Sum time intervals using linq - c#

I have a problem; actually I am having workingHours in my database table in the format HH.mm and I want to sum all the working hours using LINQ can any 1 please tell how to do this.
In totalWeekHours I have all the working hours and I have replace HH.mm format in HH:mm but I don't know how to parse it in timespan and then Sum() using Linq.
please help.
var totalWeekHours = (from twh in db.MytimeMaster
where ((twh.date >= lstsun && twh.date <= tilldate)
&& (twh.agentID == agentid))
select twh.totalworkinghours).ToList();
if (totalWeekHours.Count > 0)
{
List cnvrtToTimespanlist = new List();
foreach(var list in totalWeekHours)
{
cnvrtToTimespanlist.Add(list.ToString().Replace('.', ':'));
}
}

You can use Aggregate method.
var sum = (from twh in db.MytimeMaster
where ((twh.date >= lstsun && twh.date <= tilldate) && (twh.agentID == agentid))
select twh.totalworkinghours).Aggregate(TimeSpan.FromMinutes(0), (total, next) => total + next);
p.s. assume used TimeSpan for time intervals.

Related

Linq simple query improvement

I'm a beginner in Linq queries and I'm wondering if my query can be improved one way ore another:
long vehid = json.VehicleId.Value;
DateTime date = DateTime.Parse(json.date.Value);
var Alerts = (from t2 in entities.Alerts.AsNoTracking()
where
t2.GeneratedTimeLocal.Year == date.Year
&& t2.GeneratedTimeLocal.Month == date.Month
&& t2.GeneratedTimeLocal.Day == date.Day
&& (t2.AlertType == 2 || t2.AlertType == 3)
&& t2.vId == vid
select new
{
GeneratedTimeLocal = t2.GeneratedTimeLocal,
OptionalText = t2.OptionalText
});
return Alerts;
The problem is that the Alerts datatable has a huge amount of data in it that increases day by day and right now it's kind of slow.
The GeneratedTimeLocal field from Alerts datatable is type datetimeoffset(7).
Is there a way to improve this query?
Define a date range to improve the query. Then check the query execution plan and based on that decide if you need a new index or change existing indexes.
long vehid = json.VehicleId.Value;
DateTime dateFrom = DateTime.Parse(json.date.Value).Date; // date with no time
DateTime dateTo = dateFrom.AddDays(1); // add one day to create the date range
var Alerts = (from t2 in entities.Alerts.AsNoTracking()
where
t2.GeneratedTimeLocal >= dateFrom
&& t2.GeneratedTimeLocal <= dateTo
&& (t2.AlertType == 2 || t2.AlertType == 3)
&& t2.vId == vid
select new
{
GeneratedTimeLocal = t2.GeneratedTimeLocal,
OptionalText = t2.OptionalText
});
return Alerts;
On the other hand, remember that this query won't be executed until you do a ToList(), for example.
Try this index:
CREATE INDEX IX_Alert_GeneratedTimeLocal_vId_AlertType_with_include ON Alert(GeneratedTimeLocal, vId, AlertType) INCLUDE(OptionalText)
I'm assuming you're using SQL Server. You could also try a filtered index if the table is huge. Check out this link: https://learn.microsoft.com/en-us/sql/relational-databases/indexes/create-filtered-indexes

Retrieve rows between the date range based on total days

I've a IQueryable result queried from the db using LINQ, now I had to filter all the rows based on a field date_sent. No. of days should be calculated from date_sent to current date. this total no. of days that falls undet 0 to 30 days range should be retrieved. How do I do it. I have the below code but it's not working. no errors but does not filter properly.
query = query.Where(x => x.DATE_SENT != null);
query = query.Where(x => (int)(EntityFunctions.DiffDays(currentDate, (DateTime)x.DATE_SENT)) >= 0 &&
(int)(EntityFunctions.DiffDays(currentDate, (DateTime)x.DATE_SENT)) <= 30);
Any guidance on how it can be handled will be great.
You can get it using this query.
var dtDiff = DateTime.Now.AddDays(-30);
query = query.Where(z=> z.DATE_SENT >= dtDiff);
31-60 days
var dtDiff31 =DateTime.Now.AddDays(-31);
var dtDiff60 =DateTime.Now.AddDays(-60);
query = query.Where(z=> z.DATE_SENT >= dtDiff60 && z.DATE_SENT <= dtDiff31 );
It seems you just want to filter by a range of dates:
DateTime filterDate = currentDate.AddDays(-30);
query = query.Where(x => x.DATE_SENT >= filterDate);
In case your currentDate can vary you add the second condition:
query = query.Where(x => x.DATE_SENT >= filterDate && x.DATE_SENT < currentDate);

LINQ Statement foreach hour in day issue

I have the following statement that is taking a long time to load. Can anyone advise me how i can solve this performance issue and still get the same result a count for each hour. I have to loop though each machine first and loop through each hour for each machine.
foreach (string MachineID in this.lboxMachines.SelectedItems)
{
if (this.lboxMachines.SelectedItems.Contains(GimaID))
{
{
for (int i = 0; i <= 23; i++)
{
var PartsCast = (from p in ProductionEntity.PARTDATAs
where p.DATE_TIME >= StartDate
where p.DATE_TIME <= EndDate
where p.MACHINE == MachineID
select p).Count();
StartDate.AddHours(1);
DT.Rows[row][col] = PartsCast;
col++;
}
}
}
}
Would i be better doing one statement for each machine or leave it how it is?
I believe you are having the code get things multiple times due to IQueryable nature of Linq which would be causing the slow down. Let us break it down into steps to see if we can lesson the impact.
One needs to nail down what is not changing by getting it into a list and away from IQueryable. In the example below, I am ignoring where the data is going, just giving you the processing needed and a structure to extract the info.
// Get the machines to process only once by not getting a queryable.
var machines =
this.lboxMachines.SelectedItems
.Where( machine => machine.Contains(GimaID) )
.ToList(); // Don't keep this IQueryable but as a hard list by this call.
// Get *only* the parts to use; using one DB call
var parts = ProductionEntity.PARTDATAs
.Where(part => machines.Contains(part.Machine))
.ToList();
// Now from the parts get the count based off of the time each hour
var resultPerHour =
Enumerable.Range(0, 24)
.Select (hour => new
{
Hour = hour,
Count = parts.Count(part => part.DATETIME >= StartDate.AdHours(hour) && part.DATETIME <= EnDate)
});
resultPerHour can now be reported to the user.
Note if parts result is too big for the memory, then remove the .ToList on it and use it as IQueryable.
Based on you code try this
if (this.lboxMachines.SelectedItems != null && this.lboxMachines.SelectedItems.Contains(GimaID))
{
foreach (string MachineID in this.lboxMachines.SelectedItems)
{
for (int i = 0; i <= 23; i++)
{
var PartsCast = (from p in ProductionEntity.PARTDATAs
where p.DATE_TIME >= StartDate
where p.DATE_TIME <= EndDate
where p.MACHINE == MachineID
select p).Count();
StartDate = StartDate.AddHours(1);
DT.Rows[row][col] = PartsCast;
col++;
}
}
}
but i don't see where you define variables row, col and StartDate.
You could query all in one go by doing .Where(p => p.DATE_TIME >= StartDate && p.DATE_TIME <= END_DATE).GroupBy(p => p.DATE_TIME.Hour)

Return date records to nearest minute using linq

How do I return a list of dates to the nearest minute. I need the linq query to return only dates the match the passed date to the nearest 3 minutes
return EntitySet.Count(f => f.VISITDATE == dt.Date);
I use the code like this usually:
if((date2 - date1).Minutes <= 3) {
Console.WriteLine("Do not add again!!");
}
var dates = (from ES in EntitySet
where ES.VISITDATE >= dt.Date.AddMinutes(-3) && ES.VISITDATE <= dt.Date.AddMinutes(3)
select ES.VISITDATE)
var result = EntitySet.Where(item => Math.Abs((item.VISITDATE - dt.Date).TotalMinutes) <= 3);

c# sorting list <DateTime> and inserting to database

I´ve come to a total stop with my program and im in need of some help.
I got an xml file with customer billings and billing dates. This file has about 4000 billing dates. What i want is to sort them so the once that is in a range of a period date of 2010-04-01 - 2011-03-31 adds to a table column named period1. And the other dates goes to period2 that is 2011-04-01 - 2012-03-31.
Ive been testing and testing this solution in diffrent ways but it wont work. Im adding all the dats to a list named dates. And trying:
if (dates.All(date => date >= startDatePeriod1 && date <= stopDatePeriod1))
{
adapterBonus.InsertPeriod1Query(// insert to database));
}
else if (dates.All(date => date >= startDatePeriod2 && date >= stopDatePeriod2))
{
adapterBonus.InsertPeriod2Query(// insert to database));
}
startDatePeriod1 = 2010-04-01
stopDatePeriiod1 = 2011-03-31
and so on
The Enumerable.All extension method returns true if every element in the sequence verifies the condition. If dates contains dates in both periods, none of the ifs will run, because both calls to Enumerable.All will return false.
I'm not sure what you mean by "adds to a table column named period1", but if you mean to count all the dates in each period, use Enumerable.Count:
int period1Count = dates.Count(date => date >= startDatePeriod1 && date <= stopDatePeriod1);
int period2Count = dates.Count(date => date >= startDatePeriod2 && date <= stopDatePeriod2);
adapterBonus.InsertPeriod1Query(period1Count);
adapterBonus.InsertPeriod2Query(period2Count);
What you are doing, is the following:
Check whether ALL dates are in period one. If so, insert them into period 1 in the database. If not, check whether ALL dates are in period two and insert them into period 2 in the database.
You want to do the following:
foreach (var period1Date in dates.Where(date => date >= startDatePeriod1 &&
date <= stopDatePeriod1))
{
adapterBonus.InsertPeriod1Query(// insert period1Date to database));
}
foreach (var period2Date in dates.Where(date => date >= startDatePeriod2 &&
date <= stopDatePeriod2))
{
adapterBonus.InsertPeriod2Query(// insert period2Date to database));
}
BTW: I fixed an error in your second condition. It should be date <= stopDatePeriod2 instead of date >= stopDatePeriod2!
All return a boolean specifying whether all elements satisfy a condition. What you need is a Where() to extract those you need.
Something like:
adapterBonus.InsertPeriod1Query(dates.Where(date => date >= startDatePeriod1 && date <= stopDatePeriod1));
adapterBonus.InsertPeriod2Query(dates.Where(date => date >= startDatePeriod2 && date <= stopDatePeriod2));
Try this:
var period1Dates = dates.Where(date => date >= startDatePeriod1 && date <= stopDatePeriod1);
var period2Dates = dates.Where(date => date >= startDatePeriod2 && date >= stopDatePeriod2);
foreach(var date in period1Dates)
{ adapterBonus.InsertPeriod1Query(// insert to database)); }
etc.
easiest way to do this is doing a
startDatePeriod1 = 2010-04-01;
stopDatePeriod1 = 2011-03-01;
startDatePeriod2 = 2011-04-01;
stopDatePeriod2 = 2012-03-01;
foreach(DateTime d in dates) {
if (d => startDatePeriod1 && d <= startDatePeriod1) {
adapterBonus.InsertPeriod1Query(// insert to database));
} else if(d => startDatePeriod2 && d <= stopDatePeriod2) {
adapterBonus.InsertPeriod2Query(// insert to database));
}
}
seems like you just need a simple query for each bonus period, something like ...
var period1Dates = date.Where(date => date >= startDate1 && date <= stopDate1);
var period2Dates = date.Where(date => date >= startDate2 && date <= stopDate2);
adapterBonus.InsertPeriod1(period1Dates);
adapterBonus.InsertPeriod2(period2Dates);
As Daniel says, you're checking if all the dates are within each period, which it sound like will never be true, so nothing will be happening.

Categories

Resources