Getting all orders that are from this month - c#

Here my current month:
model.SalesForMonth = orders.Where(o => o.DateOfPayment.Value.Month == DateTime.Now.Month)
.Select(o => o.Total)
.Sum();
This is not working as expect as it's also fetching orders that happened last year at the same month.
Sure I could compare year and month, but there must be a more expressive solution I'm not familiar with.
How can I do this cleanly using Linq? (Not sure if relevant but orders is an IQueryable from Entity Framework)

The simplest way would be to create a start and end point:
// TODO: Consider what time zone you want to consider the current date in
var today = DateTime.Today;
var start = new DateTime(today.Year, today.Month, 1);
var end = start.AddMonths(1); // Exclusive end-point
var query = orders.Where(o => o.DateOfPayment.Value >= start &&
o.DateOfPayment.Value < end)
.Sum(o => o.Total)

I'm not sure what you want. You must compare year too to be sure that orders are from this year.
I think you can do it this way with linq:
model.SalesForMonth = orders.Where(o => (o.DateOfPayment.Value.Month == DateTime.Now.Month
&& o.DateOfPayment.Value.Year == DateTime.Now.Year))
.Select(o => o.Total)
.Sum();

Related

How to compare date value only in LINQ

I am trying to get the records from database where StartTime field should be today's date.
service.GetAll().Where(o => o.StartTime. == DateTime.Today.Date).Select(o => new SelectableItem(o.Id, o.TestPurpose, v == o.Id))
The date in database is of this format.
2016-07-01 07:00:00.000
How do I compare this format with today's date, I need to compare only date and not the time.
You can use approach specified by #Renan Araujo.
Or another way is, define two dates and use
.Where(o => o.StartTime >= date1 && o.StartTime < date2)
where
date1 = DateTime.Today.Date; // (lets say today's date=10-13-2016 )
date2 = DateTime.Today.AddDays(1).Date; // (tomorrow's date = 10-14-2016)
Use EntityFunctions.TruncateTime to remove the time portion:
service.GetAll()
.Where(o => EntityFunctions.TruncateTime(o.StartTime) == EntityFunctions.TruncateTime(DateTime.Today.Date))
.Select(o => new SelectableItem(o.Id, o.TestPurpose, v == o.Id))

How do I find all parent objects that do not have child object with specific property?

I have the following entities: Trackings, Ranks
Each Tracking can have 0 or more Ranks. Each Rank has a property called RankDateTime.
I need to find all trackings that have no ranks for today.
This is what I have been trying:
Attempt 1
var myTrackings = from track in DBContext.Trackings
join r in DBContext.Ranks on track.TrackingId equals r.TrackingId
where r.RankDateTime < DateTime.Today select track;
Attempt 2
var myTrackings3 =
DBContext.Trackings.Where(t => t.Ranks.Any
(r => r.RankDateTime.Date != DateTime.Today.Date));
I'm a bit confused here and my intuition is telling me I'm doing something wrong here.
What's the correct way of querying this?
Thanks in advance.
Assuming there are no RankDateTimes in the future this should work
var myTrackings3 = DBContext.Trackings.Where
(t => !t.Ranks.Any(r => r.RankDateTime.Date >= DateTime.Today.Date));
You're looking for for trackings of which all ranks are not for today:
var today = DateTime.Today;
var myTrackings3 = DBContext.Trackings
.Where(t => t.Ranks.All(r => r.RankDateTime < today));
Or, if there are future rankings:
var today = DateTime.Today;
var tomorrow = today.AddDays(1);
var myTrackings3 = DBContext.Trackings
.Where(t => t.Ranks.All(r => r.RankDateTime < today
&& t.Ranks.All(r => r.RankDateTime >= tomorrow
));
I deliberately avoid using r.RankDateTime.Date, because this would make the expression not sargable, i.e. it would disable any indexes on RankDateTime.

How to group a list of data into year, season, month, week, day?

I am dealing with big data of years.
The data model is quite simple:
public class ValueData
{
public DateTime TimeRecorded {get; set;}
public double ValueRecorded {get; set;}
}
After having a list of ValueData: List<ValueData> for years of data, I need to group the data based on: Year ==> contains data of 4 seasons: Season ==> A season contains 4 months ==> A month contains data of 4 weeks ==> A week contains data of 7 days based on the week calendar numbers of a year. Because I need to make a sum of data per year, per season, per month, per week and per day
How can I achieve this data classification? should I use LinQ?
I guess you are looking for something like conditional groups
but 2gbs of data will take a while to process.
I guess it's ok for a one time parse and save the results but if you need to run this often you'll need a more appropriate solution.
I believe you want something along the lines of the following query:
var groups = data.GroupBy(v => new {Year = v.TimeRecorded.Year,
Season = SeasonFromMonth(v.TimeRecorded.Month),
Month = v.TimeRecorded.Month,
Week = System.Globalization.CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(v.TimeRecorded, System.Globalization.CalendarWeekRule.FirstDay, System.DayOfWeek.Monday),
Day = v.TimeRecorded.Day});
With a helper function SeasonFromMonth that accepts the integer month and returns some value (probably an enum) indicating the season.
You can then select relevant subgroups with queries like:
var fallValues = groups.Where(g => g.Key.Season == Seasons.Fall);
var decemberValues = groups.Where(g => g.Key.Month == 12);
var firstOfMonth = groups.Where(g => g.Key.Day == 1);
and so on, or flatten the groups into a single list by adding a SelectMany clause (although the SelectMany will throw away the key information):
groups.Where(g => g.Key.Season == Seasons.Fall).SelectMany(g => g);
groups.Where(g => g.Key.Month == 12).SelectMany(g => g);
groups.Where(g => g.Key.Day == 1).SelectMany(g => g);

LINQ - How to query a range of effective dates that only has start dates

I'm using C# 3.5 and EntityFramework. I have a list of items in the database that contain interest rates. Unfortunately this list only contains the Effective Start Date. I need to query this list for all items within a range.
However, I can't see a way to do this without querying the database twice. (Although I'm wondering if delayed execution with EntityFramework is making only one call.) Regardless, I'm wondering if I can do this without using my context twice.
internal IQueryable<Interest> GetInterests(DateTime startDate, DateTime endDate) {
var FirstDate = Context.All().Where(x => x.START_DATE < startDate).Max(x => x.START_DATE);
IQueryable<Interest> listOfItems = Context.All().Where(x => x.START_DATE >= FirstDate && x.START_DATE <= endDate);
return listOfItems;
}
If you could use a LINQ query, you can use let to do this:
(from c in dbContext.Table
let firstdate = dbContext.Table.Max(i => c.StartDate < startDate)
where c.StartDate >= firstdate
and c.StartDate <= enddate
select c)
I'm not sure if the max will work this way, so you may need to alternatively do:
(from c in dbContext.Table
let firstdate = dbContext.Table.Select(i => i.StartDate).Max(i => c.StartDate < i)
where c.StartDate >= firstdate
and c.StartDate <= enddate
select c)
Something like that.
I haven't tried this on EF but on Linq to objects it works fine:
var result = source
.OrderBy(x => x.start)
.GroupBy(x => x.start < startDate)
.SelectMany((x, i) => i == 0 ? new[] {new { value = x.Last().value, start = x.Last().start }} : x.Where(y => y.start < endDate));
The issue is that C# LINQ is missing an operator which gives you access to the previous item in a sequence. F# apparently can handle this. Workarounds involved either a GroupBy or an Aggregate operation. In this case, GroupBy can handle it.
It's not pretty and I wouldn't recommend using it over the two phase approach.

C# LINQ query to select only first date in a month from List<DateTime>

I have a List which contains dates from June 1, 2009 to June 1, 2014. How would I query it in C# LINQ to select only the first date of each month?
Your question is slightly ambiguous. If you want the first item appearing in the list in each month, you can use:
var result = list.GroupBy(x => new { x.Year, x.Month })
.Select(x => x.Min());
The simplest way I think is to filter by the Day property of your dates:
var firstDays = dates.Where(d=> d.Day == 1);
Like this:
dates.Where(d => d.Day == 1);
Or, using query comprehension,
from d in dates where d.Day == 1 select d;
Try the following
public static bool IsFirstDayOfMonth(this DateTime t) {
var other = new DateTime(t.Year,t.Month,1);
return other == t.Date;
}
var allDates = GetTheDates();
var filter = allDates.Where(x => x.IsFirstDayOfMonth());

Categories