I am trying to compare dates in my linq query but my c.DateRequired is a nullable date field and I want to just compare the date without the time. How do I go about converting c.DateRequired in this case to just get the date.
IEnumerable<SalesOrder> salesOrders = _uow.Repository<SalesOrder>().Query()
.Filter(c => c.IsDeleted != true &&
(((c.DateRequired == DateTime.Today.Date)) && Period == 1) ||
(((c.DateRequired >= sDateP && c.DateRequired <= stDate)) &&
(Period == 2 || Period == 3)))
.OrderBy(q => q.OrderBy(c => c.DateCreated))
.Get()
.Select(p => new
{
SalesOrder = p,
SalesOrderDetailsList =
p.SalesOrderDetailsList.Where(pd => pd.IsDeleted != true),
salesOrderDetailsComponentsList =
p.SalesOrderDetailsList.Select(c => c.SalesOrderDetailsComponentsList),
SalesOrderDetailsComponentsInfoList =
p.SalesOrderDetailsList.Select(
i =>
i.SalesOrderDetailsComponentsList.Select(
info => info.SalesOrderDetailsComponentsInfoList))
})
.ToList()
.Select(p => p.SalesOrder);
return salesOrders;
}
Try to use something like this:
.Where(x => x.DateRequired.HasValue &&
EntityFunctions.TruncateTime(x.DateRequired.Value) == EntityFunctions.TruncateTime(DateTime.Today))
.ToList();
It works perfectly for me.
you need to use EntityFunctions.TruncateTime which accept a nullable datetime to truncate time in linq
EntityFunctions.TruncateTime(x.DateRequired) == EntityFunctions.TruncateTime(DateTime.Today)
I answer to a similar question.
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
I have a pretty complicated linq statement that gets a list of people (using Entity Framework) and I want to add an OrderBy clause to the end, depending on which column the user has clicked on for sorting. I DON'T want to get all the people and then sort as there are potentially alot of people and we also do paging, so getting the data and then sorting/paging is not an option. It must therefore be done using LINQ to EF.
I have managed to get the search criteria that filters based on the status of the user's current vaccination status, but I am unable to "convert" that to an OrderBy statement
The data I am getting relates to COVID vaccinations and whether the person's vaccination status is Full, Partial, Not Disclosed or None.
The Entity Framework LINQ statement with the Where clause looks like this and It is an IQueryable<Person>, not a List<Person>:
people.Where(p => p.Encounters.Where(e =>
e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
.EncounterItems.Where(ei =>
ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
(a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
))))).FirstOrDefault()
!= null)
From the above it will filter the people where their vaccination status is "Overdue". i.e they have done either Partial or Full Vaccination but the cycle for this vaccination has been exceeded. There are 2 questions with questioncode's "qIDateP" (partial) and "qIDateF" (full).
I know the below OrderBy is completly wrong, but I want to do something like this so that all the people with overdue vaccination status's are at the top. I will then add several other OrderBy clauses such as "Current" using the same clause, just chainging the date expression e.g. DbFunctions.AddMonths(a.adate, procedureCycleDays) >= DateTime.Today
people.OrderBy(p => p.Encounters.Where(e =>
e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
.EncounterItems.Where(ei =>
ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
(a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
))))).FirstOrDefault()
!= null)
The Relationships for the EF Models is as follows:
Person => Encounter => EncounterItem => PersonAssessment => Answer
A person can answer multiple Assessments over their life and can change their mind as to whether they want to disclose their vaccination status or not.
NOTE: We are using the latest Entity Framework 6.4.4
I hope someone can help me with the OrderBy clause as Im at a complete loss as to how to achieve this.
------UPDATE 1-------
I have used this so far.
people.OrderBy(p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item
.EncounterItems.DefaultIfEmpty().FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)
The issue is that all the "Overdue" records are at the bottom, not at the top. If I use OrderByDescending it seems correct. How can I now put all those records at the top with OrderBy instead of OrderByDescending.
------ UPDATE 2 Final Solution ------
After a couple of changes based on Margus answer below I have the final updated OrderBy. I had to OrderBydescending for some reason in order to get the records that I wanted at the top.
people.OrderByDescending(p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item.EncounterItems.DefaultIfEmpty().FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)
Now Im concerned about the performance lol... But that will be another stackoverflow search :)
Well as far as I can tell you want to use orderBy and then simply fetch the first element, while you could simply fetch the first element with the same predicate dropping O(nlogn) complexity
var result = people.Where(
p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.FirstOrDefault(e => e.servicedt ?? e.planneddt) // you have 1 Encounters item
.EncounterItems.FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))));
I have to fix a query which was already written in the LINQ Lambda, I found the fix in a Simple SQL Query but now I have some trouble in converting it to LINQ Query,
Here is my SQL Query
select * from RequestItem_SubRequestItem x
where x.RequestItem_key = 1 and x.SubRequestItem_key in (
select o.SubRequestItem_key
from SubRequestItem_Entitlement o
inner join SubRequestItem sr on sr.SubRequestItem_key = o.SubRequestItem_key
where o.Entitlement_key = 2 and sr.Action = 'Add' )
And below is my LINQ C# code where I am trying to insert my fixes which include inner join.
z.Entitlements = ARMContext.Context.SubRequestItem_Entitlement
.Where(o => o.Entitlement_key == z.AccessKey && !o.Role_key.HasValue && o.Entitlement.EntitlementConfiguration.UserVisible == true
&& (ARMContext.Context.RequestItem_SubRequestItem
.Where(x => x.RequestItem_key == requestItemKey)
.Select(y => y.SubRequestItem_key)
.Contains(o.SubRequestItem_key)))
.Join(ARMContext.Context.SubRequestItems, subrq => subrq.SubRequestItem_key, temp => requestItemKey, (subrq, temp) => subrq == temp)
Where as previously the C# LINQ code looked like this
z.Entitlements = ARMContext.Context.SubRequestItem_Entitlement
.Where(o => o.Entitlement_key == z.AccessKey && !o.Role_key.HasValue && o.Entitlement.EntitlementConfiguration.UserVisible == true
&& (ARMContext.Context.RequestItem_SubRequestItem
.Where(x => x.RequestItem_key == requestItemKey)
.Select(y => y.SubRequestItem_key)
.Contains(o.SubRequestItem_key)))
When I try to insert the JOIN in the LINQ as per my conditions then I get to see this error.
What is my mistake? Can anybody tell me a correct way to do it?
I think this should Suffice your need, although you might have to make changes to the other code which are dependent on your SubRequestItem_Entitlement table with {user, add}
please have a look at that. As I am sure you will have to make those changes.
.Join(ARMContext.Context.SubRequestItems, user => user.SubRequestItem_key, subreqItems => subreqItems.SubRequestItem_key, (user, subreqItems) => new { user, subreqItems })
.Where(Action => Action.subreqItems.Action == z.ApprovalAction)
you can use this query. I exactly matched the SQL query
var query = ARMContext.Context.RequestItem_SubRequestItem
.Where(a => a.RequestItem_key == 1 && a.RequestItem_key == (ARMContext.Context.SubRequestItem_Entitlement
.Join(ARMContext.Context.SubRequestItems,
right => right.SubRequestItem_key,
left => left.SubRequestItem_key,
(right, left) => new
{
right = right,
left = left
})
.Where(x => x.right.Entitlement_key == 2 && x.left.Action == "Add" && x.right.SubRequestItem_key == a.RequestItem_key).Select(y => y.right.SubRequestItem_key)).FirstOrDefault());
I have the following SQL script which works fine and pretty fast:
select top 30 CONVERT(date, p.DateCreated) as Fecha,
(select count(*) from People d where d.recipientid = p.recipientid and d.SubscriptionType = 0 and CONVERT(date, p.DateCreated) = CONVERT(date, d.DateCreated)) as Subscribed
from People p
where p.RecipientId = '276643679047355'
group by CONVERT(date, p.DateCreated), p.RecipientId
order by CONVERT(date, p.DateCreated) desc;
However, when I'm trying to call this from a C# application using LinQ, it doesn't respond as expected (as a matter of fact, after waiting 5min, I must say it doesn't respond at all). I came up with the following LinQ command, nevertheless, something has to be wrong because its not responding as fast as the SQL script provided:
model = await _context.People
.Where(x => x.RecipientId == recipientId && x.DateCreated > startDate && x.DateCreated < endDate)
.Select(x => new { DateGrouped = x.DateCreated.ToString("yyyy-MM-dd"), x.RecipientId })
.GroupBy(x => new { x.DateGrouped, x.RecipientId })
.Select(a => new StatsViewModel
{
DateStatsFormatted = a.Key.DateGrouped,
Subscribed = _context.People.Where(d => d.RecipientId == a.Key.RecipientId && d.SubscriptionType == SubscriptionType.Suscribed && d.DateCreated.ToString("yyyy-MM-dd") == a.Key.DateGrouped).Count()
}
)
.ToListAsync();
Could you please help me to point out what I'm doing wrong or, at least, suggest me what to search?
Well, after a long afternoon trying different approaches, I've finally figured it out.
I couldn't get to work my SQL profiler because my database is on Azure and it seems its not compatible. Date formatting wasn't my solution neither. The issue was on my nested query for "Subscribed" property... it seems it was creating a sort of circular reference.
Here is the way is works now:
model = await _context.People
.Where(x => x.RecipientId == recipientId && x.DateCreated > startDate && x.DateCreated < endDate)
.Select(x => new { DateGrouped = x.DateCreated.ToString("yyyy-MM-dd"), x.RecipientId, x.SubscriptionType })
.GroupBy(x => new { x.DateGrouped, x.RecipientId })
.Select(a => new StatsViewModel
{
DateStatsFormatted = a.Key.DateGrouped,
Subscribed = a.Count(c=>c.SubscriptionType == SubscriptionType.Suscribed),
Unsubscribed = a.Count(c=>c.SubscriptionType == SubscriptionType.Unsuscribed),
NoSet = a.Count(c=>c.SubscriptionType == SubscriptionType.NoSet)
}
)
.ToListAsync();
Notice that I've only added a property "SubscriptionType" on my main select in order to use it later on the filtered select as part of the filter of the "Subscribed" property... pretty simple, straight forward and works like a charm!
I am getting a list of my database, selecting certain things, then i want to query another database where the original list contains this databases job reference
var jobRefs = context.jobs.Where(j => j.LSM_Status == null &&
j.despatched_time == null
)
.Select(x => new { x.job_ref, x.volumes_env, x.postout_deadline , x.UniqNo })
.ToList();
var UpdatedRefs = context.customerslas.Where(c => jobRefs.Any(z=>z.job_ref == c.job_ref) &&
(c.invoiced == 1 ||
c.invoiced == 2) &&
c.active == 1)
.Select(c => c.job_ref)
.ToList();
And get this error
Unable to create a constant value of type 'Anonymous type'. Only primitive types or enumeration types are supported in this context.'
The ToList() in the first first query is fetching data to a collection in memory while the second query, where you compare the data, is in database. To solve this you need to make them in the same area, either db or memory.
Easiest way, and recommended, would be to just remove ToList() from the first query
var jobRefs = context.jobs.Where(j => j.LSM_Status == null &&
j.despatched_time == null
)
.Select(x => new { x.job_ref, x.volumes_env, x.postout_deadline , x.UniqNo });
var UpdatedRefs = context.customerslas.Where(c => jobRefs.Any(z=>z.job_ref == c.job_ref) &&
(c.invoiced == 1 ||
c.invoiced == 2) &&
c.active == 1)
.Select(c => c.job_ref)
.ToList();
I have the following Linq to Entity:
var details = Uow.EmployeeAttendances.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId && a.Timestamp == summary.Date)
.ToList();
summary.Date is just the date part so the value is like this: '2014-07-20 00:00:00'
The problem is that a.TimeStamp is a DateTime field with both date and time.
So the above query always return empty
Any way I can convert a.TimeStamp just to Date so I can compare apples with apples?
The error that I get is:
The specified type member 'Date' is not supported in LINQ to Entities
Appreciate it.
DateTime fields have a Date property, so we can simply do:
var details =
Uow
.EmployeeAttendances
.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId
&& a.TimeStamp.Date == summary.Date)
.ToList();
The right solution is:
In Entity Framework 6, you have to use DbFunctions.TruncateTime.
var dates = Uow.EmployeeAttendances.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId && System.Data.Entity.DbFunctions.TruncateTime(a.Timestamp) == attendanceDate)
.OrderBy(a=> a.Timestamp)
.ToList();
As an alternative to using DbFunctions.TruncateTime, you can simply do the following:
var from = summary.Date;
var to = summary.Date.AddDays(1);
var details = Uow.EmployeeAttendances
.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId && a.Timestamp >= from && a.Timestamp< to)
.ToList();
Try it
string f = summary.ToString("MM/dd/yyyy");
summary= Convert.ToDateTime(f); // time at 12:00 start date
var details = Uow.EmployeeAttendances.GetAllReadOnly()
.Where(a=>a.EmployeeId== summary.EmployeeId &&
a.Timestamp == summary).ToList();
you can use DateTime.Compare
for example
var details = Uow.EmployeeAttendances.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId && DateTime.Compare(x.Timestamp .Date, summary.Date) == 0).ToList();
or use EntityFunctions
var details = Uow.EmployeeAttendances.GetAllReadOnly()
.Where(a => a.EmployeeId == summary.EmployeeId && EntityFunctions.TruncateTime(x.Timestamp)== EntityFunctions.TruncateTime(summary.Date)).ToList();