I am trying to compare dates in Entity Framework 6 LINQ Query.
var bookings = context.Bookings.Include("BookingItems").Where(x=>x.IsDeleted == false && DateTime.Compare(DbFunctions.TruncateTime(x.BookingDate).Value,DateTime.Now.Date)==0).ToList();
However its resulting in Exception:
"The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."
I just want to compare dates by trimming time part.
Any suggestions how this can be done?
Linq can't translate some native .Net code into Sql so try to use DateTime.Now function and other .Net function outside Linq query and then reference it in query.
String currentTime = DateTime.Now.ToShortDateString();
var bookings = context.Bookings.Include("BookingItems").Where(x=>x.IsDeleted == false && DateTime.Compare((x.BookingDate).Value.Date,currentTime)==0).ToList();
I haven't run though there might be some syntax error, but try anyway
Linq to sql or sql does not have implemination DateTime.Compare
Try converting to collection.
var bookings = context.Bookings.Include("BookingItems").ToList().Where(x=>x.IsDeleted == false && DateTime.Compare(DbFunctions.TruncateTime(x.BookingDate).Value,DateTime.Now.Date)==0).ToList();
Related
I've searched through numerous examples on how to filter collection based on another collection and I have found an easy way, like so:
var oShipnotes = await DbContext.ShipNotes.Where(s => oManageRouteDto.ShipNotes.Any(mr => mr.Id == s.Id)).ToListAsync();
however it throws an exception that says it cannot be translated to SQL query.
Could anyone point me the right direction how to solve this?
Thanks!
Replace nested LINQ query to materialized list of identifiers:
// 1) get the list of target ship note identifiers
var ids = oManageRouteDto.ShipNotes.Select(mr => mr.Id).ToList();
// 2) pass this list into Where using Contains
var oShipnotes = await DbContext.ShipNotes.Where(s => ids.Contains(s.Id)).ToListAsync();
EF is aware of this pattern and translates IList<T>.Contains into SQL's IN condition.
Since EF deals with IQueryables, each LINQ query must be translated into valid SQL expression. As a result, EF and underlying provider cannot translate every valid LINQ query (from C# perspective) just because SQL is not C#.
_dbEntities.EmployeeAttendances.Where(x => x.DailyDate.Date.Equals(DateTime.Now.Date)).ToList();
"The specified type member 'Date' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported."
How can i do this get employees data on based on current date in linq query?
EntityFramework cannot convert DateTime.Date to SQL. So, it fails to generate expected SQL. Instead of that you can use EntityFunctions.TruncateTime() or DbFunctions.TruncateTime()(based on EF version) method if you want to get Date part only:
_dbEntities.EmployeeAttendances
.Where(x => EntityFunctions.TruncateTime(x.DailyDate) == DateTime.Now.Date)
.ToList();
Additional info:
EntityFunctions methods are called canonical functions. And these are a set of functions, which are supported by all Entity Framework providers. These canonical functions will be translated to the corresponding data source functionality for the provider. Canonical functions are the preferred way to access functionality outside the core language, because they keep the queries portable.
You can find all canonical functions here and all Date and Time Canonical Functions here.
Update:
As of EF6 EntityFunctions has been deprecated for System.Data.Entity.DbFunctions.
Dont use EntityFunctions in EF 6. TruncateTime is in the DbFunctions class:
DbFunctions.TruncateTime(x.DailyDate)
If the DailyDate property is already just a date, instead of a date and time, then it would be simplest to just use:
// Outside the query so it becomes a constant, effectively
var today = DateTime.Today;
var employees = _dbEntities.EmployeeAttendances
.Where(x => x.DailyDate == today)
.ToList();
If it does have times (making the above fail), you could always use:
// Outside the query so it becomes a constant, effectively
var today = DateTime.Today;
var tomorrow = today.AddDays(1);
var employees = _dbEntities.EmployeeAttendances
.Where(x => x.DailyDate >= today &&
x.DailyDate < tomorrow)
.ToList();
... or use TruncateTime as Farhad's answer suggests. I'd still recommend evaluating DateTime.Today first though:
var today = DateTime.Today;
var employees = _dbEntities.EmployeeAttendances
.Where(x => EntityFunctions.TruncateTime(x.DailyDate) == today)
.ToList();
Note that Today (like DateTime.Now) uses the system default time zone. You should think carefully about whether that's what you want.
Just in case it helps someone...
In EF 6, EntityFunctions is obsolete, use DbFunctions class instead.
You might want to include the Namespace System.Data.Entity;
eg:
_dbEntities.EmployeeAttendances.Where(x => DbFunctions.TruncateTime(x.DailyDate) == DateTime.Now.Date).ToList();
In dev environment the following SQL statement is working but not on any other environment:
System.NotSupportedException: LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.
Related code:
bool hasSomethinglast14days = (from a in db.someTable
where a.SomeIntColumn == someIntVariable
&& a.CreateDate >= DateTime.UtcNow.AddDays(-14)
select a.someColumn).Any();
The provider you're using is unable to translate the AddDays() method into a valid SQL statement.
Since the date you're subtracting from doesn't depend on any values from the database anyway, just do your subtraction first (outside of the query), then use the resulting value:
var pastDate = DateTime.UtcNow.AddDays(-14);
bool hasSomethinglast14days = (from a in db.someTable
where a.SomeIntColumn == someIntVariable
&& a.CreateDate >= pastDate
select a.someColumn).Any();
As for it working in your Dev environment, I don't have an answer for that. I'm surprised it does.
This is my code:
string queryString = "Marco".ToLower();
utenti = db.User.Where(p =>
queryString.Contains(p.Nickname.ToLower()) ||
queryString.Contains(p.Nome.ToLower()) ||
queryString.Contains(p.Cognome.ToLower())).ToList();
but I get:
Only arguments that can be evaluated on the client are supported for the String.Contains method.
Why? Can't I use .Contains()?
Try .IndexOf. It is not LINQ that can't do Contains, it's LINQ to Entities and LINQ to SQL that can't.
string queryString = "Marco";
utenti = db.User.Where(p =>
queryString.IndexOf(p.Nickname, StringComparison.OrdinalIgnoreCase) >= 0 ||
queryString.IndexOf(p.Nome, StringComparison.OrdinalIgnoreCase) >= 0 ||
queryString.IndexOf(p.Cognom, StringComparison.OrdinalIgnoreCasee) >= 0)
.ToList();
Why?
LINQ uses deferred execution. This means it waits until you want to iterate over your query results before it does anything. There are 3 main types of LINQ:
LINQ to Objects - when your IEnumerable is already on the heap.
LINQ to Entities - when you want to query a database using Entity Framework.
LINQ to SQL - when you want to query a database using LINQ to SQL.
Deferred execution in the context of the second 2 means that your query is not executed on the database until you enumerate the results in a foreach block, or invoke an enumeration method like .ToList, .ToArray, etc. Until then, your query is just stored as expression trees in memory.
Your query would work just peachy if db.User was a collection in memory. However when the data is in a database, LINQ to Entities (or LINQ to SQL) must translate your expression trees to what it calls a "store expression" -- which is just fancy talk for "convert my LINQ expressions to SQL".
Now imagine you had a custom C# algorithm you wanted to use for your query, and you did something like this:
var result = db.User.Where(x => MyCustomMethod(x));
There is no way today that LINQ to Entities can convert your C# code into a SQL query (store expression). It is the same with a lot of other C# methods you rely on daily. It also does not support .ToLower, .ToUpper, .StartsWith, .EndsWith, etc. There is a limited number of C# methods that can be converted to store expressions, and .IndexOf just happens to be one of them.
However keep in mind that it is only the string object's Contains method that we are talking about here that is not supported for store expressions. LINQ to Entities does support .Contains on IEnumerables. The following is valid and will work with LINQ to Entities (not sure about LINQ to SQL):
var idsIWantToFind = new[] { 1, 2, 3 };
var users = db.Where(x => idsIWantToFind.Contains(x.UserId));
The above is the equivalent of doing a SQL WHERE UserId IN (1, 2, 3) predicate.
I need to filter my queries by dates but I don't care in this case about time portion of it that is stored in SQL Database.
I first tried to something like
var now = DateTime.Now.Date;
Where(x => x.CreatedDate.Date.Compare(now) == 0)
but this seems to all get locally checked making the query slow. How can I do this without making it do the check locally?
I am pretty much trying to just find all results that would say have happened today(2020-01-06).
There are a limited number of methods you can use on translatable types when constructing your Lambda / Linq expressions. This is because each method would need additional code so that it could be translated into a sql store expression. It means that you must check that any methods you want to use and expect to be translated into a sql store expression are supported.
In this case the DateTime.Compare is not supported.
The easiest thing to do here is a simple range comparison because the time is included in your persisted value.
var start = DateTime.Now.Date;
var end = start.AddDays(1);
Where(x => x.CreatedDate >= start && x.CreatedDate < end)
This will result in a sargable query.
Use
var now = DateTime.Now.Date
...WHERE(CreatedDate.Date == now)
I just checked that above translates to the following SQL query:
WHERE ((CONVERT(date, [x].[CreatedDate]) = '2019-01-07T00:00:00.000')
I used this (link) method to see what LINQ translates to