Comparing the dates logic in Linq - c#

I want to query the result
public resultType GetData(int ClientID, DateTime CreatedDate)
{
var Row = DB.tblPlans
.Where(m => m.fkClient_Id == ClientID && m.PlanDate <= CreatedDate)
.OrderByDescending(m => m.Id)
.FirstOrDefault();
}
But the results are not coming as required because the "m.PlanDate" in the query is comparing the time also.
so The parameter "CreatedDate" in the above function will always get "12:00:00 AM" attached to it suppose "2/17/2014 12:00:00 AM"
because it is a datepicker control and I am converting it into datetime but the value of created date with which I have to compare it is having original timing suppose "2/17/2014 11:58:35 AM"
and that is why I am not getting the desired result.
I think the result will be fine if time portions get removed.
I have searched the above problem and it have many solutions like::
using AddDays(1); but I am not sure about it's working.
also I tried::
http://www.codeproject.com/Articles/499987/LINQ-query-to-compare-only-date-part-of-DateTime
Please suggest me a better way to do this as this is not the first time I am getting this problem.

If you are using Linq to SQL (as you specified in question tag), then simply get Date part of DateTime:
var Row = DB.tblPlans
.Where(m => m.fkClient_Id == ClientID && m.PlanDate.Date <= CreatedDate)
.OrderByDescending(m => m.Id)
.FirstOrDefault();
With Entity Framework you should use EntityFunctions.TruncateTime(m.PlanDate)

Have you tried this:
public resultType GetData(int ClientID, DateTime CreatedDate)
{
var Row = DB.tblPlans
.Where(m => m.fkClient_Id == ClientID && m.PlanDate.Date <= CreatedDate)
.OrderByDescending(m => m.Id)
.FirstOrDefault();
}

The recommended way to compare dates in linq queries if you are using EntityFramework 6 is DbFunctions.TruncateTime(m.PlanDate) and for previous versions EntityFunctions.TruncateTime(m.PlanDate)

Related

LINQ - GroupBy Year/Month

I'm trying to populate graph data with total amount(sum) by a last four months, and visually it would look like this:
I've tried so far to group data by year and by a month, but I'm not sure if it's right approach cuz this doesn't work..
Here is the code:
var testQUERY = await _context.Calculation
.AsNoTracking()
.Where(x => (x.PaymentDate != null && x.PaymentDate > DateTime.UtcNow.AddMonths(-4)))
.GroupBy(x => new { x.PaymentDate.Value.Year, x.PaymentDate.Value.Month}).ToListAsync();
Here's my paymentDate :
And I'm wondering how could I group by month only..
Error I'm facing is next:
Error generated for warning
'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The
LINQ expression 'GroupBy(new <>f__AnonymousType0`2(Year =
Convert([p].PaymentDate, DateTime).Year, Month =
Convert([p].PaymentDate, DateTime).Month), [p])' could not be
translated and will be evaluated locally.'. This exception can be
suppressed or logged by passing event ID
'RelationalEventId.QueryClientEvaluationWarning' to the
'ConfigureWarnings' method in 'DbContext.OnConfiguring' or
'AddDbContext'.
P.S If I better think because I'm using
x.PaymentDate != null && x.PaymentDate > DateTime.UtcNow.AddMonths(-4)
I don't need new anonymous type where I included year also.. but obliviusly I'm trying to group by column which does not exist.. ?
Try using this one. See comments for possible fixes.
var testQUERY = await _context.Calculation
.AsNoTracking()
.Where(x => x.PaymentDate != null)
.Select(x => new { PaymentDate = x.PaymentDate.Value, Row=x }) // pre-select non-null payment date
.Where(x => x.PaymentDate > DateTime.UtcNow.AddMonths(-4)) // this should go after the grouping, as it might include from just part of the month
.GroupBy(x => new { x.PaymentDate.Year, x.PaymentDate.Month})
.Select(grp=> new { grp.Key.Year, grp.Key.Month, Count = grp.Count()) // flatten group and calculate aggregates
.ToListAsync();

Getting maximum date and return default date when table is empty

How to return date "1900/12/12 00:00:00" if table has no rows? I am trying to get max transaction date and it works well if there are rows in the table otherwise I get an error message because of date format in ToString().
string d = context.AllTransactions.Where(t => t.ID == OID)
.Max(t => t.TransactionDate).ToString("dd/MM/yyyy HH:mm:ss");
TransactionDate is NOT NULL datetime field.
Use the DefaultIfEmpty method before the .Max (and as it is linq to entities and you will not be able to create a new transaction object then first project only the dates):
var result = context.AllTransactions.Where(t => t.ID == OID)
.Select(t => t.TransactionDate)
.DefaultIfEmpty(new DateTime(1900,12,12)).Max();

Get custom string from SQL and turn into c# date object to sort by

I have a table that has a sql column with a date as a string like 'January 1, 2018'. I'm trying to turn that into a DateTime object in C# so I can use it to sort a list by. I'm currently grouping everything by the ID so I can return the highest revision. This is working great but I also need to OrderByDescending date from a the column that represents a date. The below code will order everything alphanumerically but I need to sort by DateTime.
using (dbEntities entities = new dbEntities())
{
var db = entities.db_table
.GroupBy(x => x.ID) //grouping by the id
.Select(x => x.OrderByDescending(y =>
y.REVISIONID).FirstOrDefault());
return db.OrderBy(e => e.Date_String).ToList();
}
Thanks, I appreciate any help on this!
You'll need to materialize the objects and use LINQ-to-Objects to do the conversion to a C# DateTime.
return db.AsEnumerable().OrderBy(e => DateTime.Parse(e.Date_String)).ToList();
If at all possible, I would strongly recommend changing your column to a datetime2 or datetimeoffset at the database level, though.
If you don't mind some of the work being done on the client side you could do something like this:
using (dbEntities entities = new dbEntities())
{
var db = entities.db_table
.GroupBy(x => x.ID) //grouping by the id
.Select(x => x.OrderByDescending(y =>
y.REVISIONID).FirstOrDefault()).ToList();
return db.OrderBy(e => DateTime.Parse(e.Date_String)).ToList();
}
The parsing of the DateTime needs to be modified so it matches the format in the database, but otherwise it should work.

C# - Lambda expression for selecting records based on current date?

I have a database table called Event, which has a StartDate column which stores the date the event was recorded. Therefore, I have a Lambda Expression where I want to select only those records which has the StartDate greater than the current date?
public List<Event> GetAllEvents(int Id)
{
DateTime currentDateTime = DateTime.Today;
var events = _context.Event
.Where(s => s.Id == Id)
.Select(s => s.StartDate >= currentDateTime)
.ToList();
return events;
}
I have tried the above code but its giving me an error:
Cannot Implicitly convert type 'System.Collections.Generic.List'
to 'System.Collections.Generic.List'
How can I select all the records that has the StartDate greater than todays date?
Thank you
Select is not for filtering. It's for projection. Where is how you filter the data:
DateTime currentDateTime = DateTime.Today;
var events = _context.Event
.Where(s => s.Id == Id && s.StartDate >= currentDateTime)
.ToList();
But, are you sure you only want an event with a given Id? I'd expect IDs to be unique, so only one Event should match the Id. I think you should skip that condition.
DateTime currentDateTime = DateTime.Today;
var events = _context.Event
.Where(s => s.StartDate >= currentDateTime)
.ToList();
But I might be wrong, so you should check what Id means in your domain and if it makes sense to filter by StartDate after you selected Events by Id.

Entity Framework LINQ query to return a list and subset of collection satisfying certain condition

I have an entity TimesheetHeader which has a User object, and start date and end date corresponding to the week of timesheet entry, and an ICollection of TimesheetEntry.
TimesheetEntry is another entity which contains a Project entity, date and hours object (each TimesheetEntry basically records the number of hours the user worked on a project on a day).
I have to generate a report to find out the various users and breakdown of hours worked on each day on a particular project.
Currently my logic is to first get a list as follows:
context.TimesheetHeader.Where(u => u.status.statusName != "deleted" && DbFunctions.TruncateTime(u.StartDate) >= dateStart && u.TimesheetEntry.Any(te => te.projectId == report.project)).ToList();
But this basically returns a TimesheetHeader and all its TimesheetEntry if there is at least one TimesheetEntry corresponding to the project.
Then I have to loop and filter the result.
Is there a better solution to this where I can directly get the result from the query itself, where I get the TimesheetHeader and only the subset of relevant TimesheetEntry corresponding to the project
Does this work? I also suggest pluralizing your collections so it's more clear which end of the relationship you're on.
context.TimesheetHeaders
.Where(u => u.status.statusName != "deleted")
.Where(u => DbFunctions.TruncateTime(u.StartDate) >= dateStart)
.Where(u => u.TimesheetEntries.Any(te => te.projectId == report.project))
.Select(u => new {
TimeSheetHeader = u,
TimeSheetHeaderEntries = u.TimesheetEntries.Where(te => te.projectId == report.project)
})
As Gert Arnold answered here
you can try as below by adding where clause to your include :
context.TimesheetHeader.Where(u => u.status.statusName != "deleted" &&
DbFunctions.TruncateTime(u.StartDate) >= dateStart).Select(t => { t, TimesheetEntries = t.TimesheetEntry.Where(te => te.projectId == report.project)).AsEnumerable()
.Select(x => x.t)
.ToList();
Or look at EntityFramework-Plus. It might be useful.

Categories

Resources