I am using date in where clause in Entity Framework and getting following error:
It is due to the below code:
var entity = dbContext.MyTable
.Where(w => w.PId = 3 && w.CreatedOn.Date == mydate.Date)
.First();
If I convert data into list using .ToList(), then compare to date, it will work fine but if I do so then it will pull data first into code then filter it out. Please help me out with this issue. Currently I am using a stored procedure to resolve the issue but really want this to work.
You can use DbFunctions.TruncateTime canonical function like this
var entity = dbContext.MyTable
.Where(w => w.PId == 3 && DbFunctions.TruncateTime(w.CreatedOn) == mydate.Date)
.First();
This is how I ended up doing Date search when I had to consider time (Hour and Minutes portion) also
var entity = dbContext.MyTable
.Where(
x => x.CreatedOn.Year == mydate.Year
&& x.CreatedOn.Month == mydate.Month
&& x.CreatedOn.Day == mydatee.Day
&& x.CreatedOn.Hour == mydate.Hour
&& x.CreatedOn.Minute== mydate.Minute
).FirstOrDefault();
you cannot compare dates directly by using .Date for this you have to use DbFunctions or EntityFunctions.
I prefer to use DbFunctions
You can use it as given below:
var entity = dbContext.MyTable
.Where(w => w.PId = 3 && DbFunctions.TruncateTime(w.CreatedOn) == DbFunctions.TruncateTime(mydate))
.First();
EF doesn't currently support translating all granular operations on objects in LINQ to an SQL query (which is what happens prior to that ToList() operation). Some things are (such as .Contains() on primitive collections). But not all things.
So, while you may have expected the query to translate to various "DATEPART" comparisons in the SQL statement, it's just not supported. You have to change your LINQ to accommodate it a bit.
One way is to evaluate the 24-hour range. This will work on either side of the ToList():
DateTime minDate = new DateTime(mydate.Date.Year, mydate.Date.Month, mydate.Date.Second);
DateTime maxDate = minDate.AddSeconds(86399);
var entity = dbContext.MyTable
.Where(w => w.PId = 3 && w.CreatedOn >= minDate && w.CreatedOn <= maxDate).First();
Related
I want to get only those employees that have at least one service, and which that service is younger than current date (dt)
I tried with .Any() but it returns me all employees with all services (it doesnt check that date)
var employees =
employeeService.GetAllActiveEmployeesForCompanyForLocation(companyId, location.Id)
.Where(x => x.IsCounter && x.Services != null && x.Services.Count > 0 &&
x.Services.Any(u => u.ActiveTo >= dt.Value));
I want to filter just those employees which have at least one service or more where ActiveTo is not in the past (dt is a current datetime.now)
You can chain multiple .Where and .Select statements after one another. Your LINQ query is very hard to read without more specific information about your objects.
To make it more readable, I would suggest splitting your requirements into separate queries, like so:
var employeesWithActiveServices =
employeeService.GetAllActiveEmployeesForCompanyForLocation(companyId, location.Id)
.Where(e => e.IsCounter && e.Services.Count >= 1)
.Select(e => e.Services.Contains(s => s.ActiveTo >= DateTime.Now)).ToList();
Notice how I removed your e.Services != null check. It is redundant when you're already checking e.Services.Count.
This was made quickly of the top of my head, so you may need to tweak it to suit your needs.
It is still a hard LINQ query to read without seeing the objects it is querying, but this at least makes the query itself more readable.
Try to remove any additional null, Count checks, otherwise SQL will be complex and slow:
var employees =
employeeService.GetAllActiveEmployeesForCompanyForLocation(companyId, location.Id)
.Where(x => x.IsCounter &&
x.Services.Any(u => u.ActiveTo >= dt.Value));
EF Core translates your query into the SQL, which do not have NullReference exception.
I'm trying to run the following query:
List<EPCRA_Events> x =
_dbContext.EPCRA_Events
.Where(e => e.DueDt.HasValue &&
(e.DueDt.Value - DateTime.Now).Days < 30)
.ToList();
But I keep getting an error
The LINQ expression ...xxx... could not be translated
After reviewing other posts I've seen a common solution is using DbFunctions class. However, after using Nuget to import Entity Framework 6.4.4 and Microsoft.EntityFrameworkCore 5.0.9, I don't have access to that class. Furthermore, the Entity class isn't in the System.Data namespace.
Any info on how I can get this query to run, or what I'm doing wrong using DbFunctions would be appreciated. Thanks.
Even if the query could be translated, it would be a bad query because it would have to calculate the difference for every single row before filtering. Indexing wouldn't help, because indexes are built from the stored values.
The solution is to calculate the cutoff date in advance and compare with the field directly.
This code will find records in the past 30 days
var cutoff=DateTime.Now.AddDays(-30);
List<EPCRA_Events> x = _dbContext
.Where(e => e.DueDt > cutoff)
.ToList();
While this will find records up to 30 days in the future :
var cutoff=DateTime.Now.AddDays(30);
List<EPCRA_Events> x = _dbContext
.Where(e => e.DueDt < cutoff)
.ToList();
While this will return records in the next 30 days, including today:
var cutoff=DateTime.Now.AddDays(30);
List<EPCRA_Events> x = _dbContext
.Where(e => e.DueDt>=DateTime.Today && e.DueDt < cutoff)
.ToList();
This will ignore NULLs and use any indexes that cover DueDt
if you use MS Sql Server you can try this
var dateTimeNow=DateTime.Now;
var x = _dbContext.EPCRA_Events.Where(e => EF.Functions.DateDiffDay(e.DueDt, dateTimeNow) < 30).ToList();
Issue: while filtering records within a date range & matching a CityID using LINQ, the query succeeds when written in 2 steps; however, it fails when combined as one query!
How can the LINQ query be rewritten so that -- it can perform both filters (i.e. match the CityId & retrieve records in the date range in the same step to improve performance?
I got it to work in two steps fine,
i.e. do a
var Step1 = db.weekRecord.Where(x => x.CityId == CityRecord.Id).ToList();
and then
Step1.Where(x => x.date.Date >= fromDate.Date
&& x.date.Date <= toDate.Date)
.ToList();
it fails when I combine them!!
// works when done in 2 steps!!
var weeklyWeather = db.weekRecord
.Where(x => x.CityId == CityRecord.Id
&& (x.date >= weekStarting && x.date <= weekEnding))
// - when combined results are NULL!??
var weeklyWeather2 =
db.weekRecord(x => x.date.Date >= fromDate.Date && x.date.Date <= toDate.Date)
.ToList();
After looking up other SO answers, I tried this TruncateTime as well... could not get it to work..
// is this correct, from SO answers, DbFunctions.TruncateTime
var testQueryRecrods = db.weekRecord
.Where(x => x.CityId == CityRecord.Id)
.Where(x =>
DbFunctions.TruncateTime(x.date.Date) >= DbFunctions.TruncateTime(fromDate.Date)
&& DbFunctions.TruncateTime(x.date.Date) <= DbFunctions.TruncateTime(toDate.Date))
.ToList();
ERROR:
[NotSupportedException: The specified type member 'Date' is not
supported in LINQ to Entities. Only initializers, entity members, and
entity navigation properties are supported.]
System.Data.Entity.Core.Objects.ELinq.MemberAccessTranslator.TypedTranslate(ExpressionConverter
parent, MemberExpression linq) +452
System.Data.Entity.Core.Objects.ELinq.TypedTranslator`1.Translate(ExpressionConverter
parent, Expression linq) +49
The question is confused, but I would assume the problem is the .Date. Unlike linq2sql, entity framework can not translate .Date to sql. But you can rewrite it like
var fromDateDate = fromDate.Date;
var toDateDate = toDate.Date;
var testQueryRecrods = db.weekRecord
.Where(x => x.CityId == CityRecord.Id)
.Where(x => DbFunctions.TruncateTime(x.date) >= fromDateDate
&& DbFunctions.TruncateTime(x.date) <= toDateDate)
.ToList();
And it would work. To some point. What EF generates is actually totally stupid in this case. Unlike linq2sql, EF generates query, that is not sargable (in my case*). It can run thousands of times slower than necessary. I would recommend to avoid the conversion to date completely:
var fromDateDate = fromDate.Date;
var toDateDate1 = toDate.Date.AddDays(1);
var testQueryRecrods = db.weekRecord
.Where(x => x.CityId == CityRecord.Id)
.Where(x => x.date >= fromDateDate
&& x.date < toDateDate1)
.ToList();
As #juharr pointed out, when you split the query, you run first half against server and the second half as linq to objects. In that case the .Date works, but you download many more records in the first half than you need.
*the datetime type may be the problem, maybe it would work better with datetime2, I did not test this scenario
An offbest suggestion is to write your own LINQ extensions for this..
public static class ext
{
//This extension compares one date to another... if you can call from Linq
public static bool GreaterThan(this DateTime self, DateTime CompareDate
{
if (self.Year > CompareDate.Year) return true;
else if ((self.Year == CompareDate.Year) && (self.Month > CompareDate.Month)
return true;
else if ((self.Year == CompareDate.Year) && (self.Month == CompareDate.Month) && (self.Day > CompareDate.Day))
return true;
return false;
}
}
I think, there is no option except using DbFunctions.TruncateTime for Linq to Entities. Because, as SQL Server query Linq to Entities should perform convertion datetime to date and the best method which can be used is DbFunctions.TruncateTime. I just debugged the DbFunctions.TruncateTime convertion and the translated query seems like;
WHERE (convert (datetime2, convert(varchar(255), [Extent1].[CreationDate], 102) , 102)) > #p__linq__0
As you see, while performing the conversation, there is a redundant string conversation here. However, the EF would convert the datetime to date in SQL just like this 'cast(CreationDate as date)'. But it is not.
So, there are two options here.
1- If you have very huge table which the performance is affected by redundant string conversations, you should build your query manually in SQL as stored procedure or something like and execute it from context.
2- If you don't have performance considerations like that; just use DbFunctions.TruncateTime(x.date)
var testQueryRecrods = db.weekRecord
.Where(x => x.CityId == CityRecord.Id)
.Where(x => DbFunctions.TruncateTime(x.date) >= fromDate.Date && DbFunctions.TruncateTime(x.date) <= toDate.Date)
.ToList();
So I'm having issues with this LINQ query I had been using for some time, and now it seems to not be working as expected.
messagesWithoutConditional =
await
MobileServiceInstance.GetSyncTable<Messages>()
.OrderByDescending(key => key.SentDate)
.Take(50)
.Where(
p =>
(p.Uuid == myUuid && p.RecipientUuid == otherUuid) ||
(p.Uuid == otherUuid && p.RecipientUuid == myUuid))
.ToListAsync();
So lets say I have this query that simply returns the last 50 messages sent between 2 parties. Now if I want to add an additional condition that the 50 messages should also be before a certain date I would expect to do something like this
messagesWithConditional =
await
MobileServiceInstance.GetSyncTable<Messages>()
.OrderByDescending(key => key.SentDate)
.Take(50)
.Where(
p =>
((p.Uuid == myUuid && p.otherUuid == recipientUuid) ||
(p.Uuid == otherUuid && p.RecipientUuid == myUuid))
&& p.SentDate < 'some date')
.ToListAsync();
Lets suppose I should expect this to return 40 messages, but it returns 0. However, if I alternate the query into this
messagesWithConditional = messagesWithoutConditional.Where(p => p.SentDate < 'some date').ToList();
then I will receive the 40 expected messages by querying the result of my original expression.
How is the second approach any different from the first? Ideally I would like to use the && operator to add a new conditional expression rather than break off into a second where clause
Edit
I should also note that the times are in UTC, and the SentDate attribute is of type DateTimeOffset
As of right now it appears to be a bug, unless some other insight is made. Please refer to the bug report for more information
.Where should be put before the .OrderByDescending and .Take(50)
I have a StudentReceipts table which stores ReceiptNo as string(001,002,003,..,099,..).
I want go get the last receiptno details inorder to increment the receiptno for next transaction.
This is what I have tried
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable()
.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
But there i am getting the following exception
this function can only be invoked from linq to entities
Any help will be highly appreciated.
By calling .AsEnumerable() you are going from Linq-To-Entities to Linq-To-Object. By calling it, you are also filtering all the results in memory, so you are pulling the whole StudentReceipts table from the database everytime you do that query as it gets executed past the .AsEnumerable() method. The general rule is to try to do as much as you can on the database side:
var _lastGeneratedRecDetails =
_db.StudentReceipts.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.AsEnumerable()
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
If you do it like this, you will filter everything in the database and fetch the filtered results. I don't know what type x.ReceiptNo is though, but calling Int.Parse isn't allowed in Linq-To-Entities. You can filter first and then call AsEnumerable to be able to do the parsing and ordering in memory.
In my case, I was re-using a Func / Filter expression that included DbFunctions.TruncateTime in a follow-up processing statement AFTER I had already processed the query in SQL. Removing it cleared the instance of the exception for me.
use and
.AsQueryable()
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable().AsQueryable()