How to use ToShortDateString in linq lambda expression? - c#

I need to call ToShortDateString in a linq query suing lambda expressions:
toRet.Notification = Repositories
.portalDb.portal_notifications.OrderByDescending(p => p.id)
.FirstOrDefault(p => p.date.ToShortDateString() == shortDateString);
but I get the error:
An exception of type 'System.NotSupportedException' occurred in
System.Data.Entity.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method
'System.String ToShortDateString()' method, and this method cannot be
translated into a store expression.
What can I do, considering that I do need to use ToShortDateString() ?
Thanks.

Linq to Entities cannot convert ToSortDateString method into SQL code. You can't call it on server side. Either move filtering to client side (that will transfer all data from server to client), or consider to use server-side functions to take date part of date (you should pass DateTime object instead of shortDateString):
EntityFunctions.TruncateTime(p.date) == dateWithoutTime

You shouldn't be forcing a string comparison when what you're working with is Date/time data - as soon as you force string comparisons, you're suddenly having to deal with how the strings are formatted.
Instead, have something like:
var endDate = targetDate.AddDays(1);
toRet.Notification = Repositories
.portalDb.portal_notifications.OrderByDescending(p => p.id)
.FirstOrDefault(p => p.date >= targetDate && p.date < endDate);
(Assuming that targetDate is whatever DateTime variable you had that was used to produce shortDateString in your code, and is already a DateTime with no time value)

Try this,
You can also used with below code.
Activity = String.Format("{0} {1}", String.Format("{0:dd-MMM-yyyy}", s.SLIDESHEETDATE), String.Format("{0:HH:mm}", s.ENDDATETIME))

ToShortDateString() method usually used to work only with date and ignore time stamps.
You will get exactly today result-set by using the following query.
Repositories.portalDb.portal_notifications.OrderByDescending(p => p.id)
.FirstOrDefault(p => p.date.Date == DateTime.Now.Date);
By using Date property of DateTime struct you can just fetch record of that date only.
Note: Linq to Objects. Only works if you CAN (or have option) to bypass ToShortDateString() method

Related

How to compare dates (stored as strings) with linq to entities?

I am trying to pull data from a database by begin/end date parameters.
However the date that I need to filter on is stored as a string in Oracle DB.
Using linq how can I filter the dates out based on my parameters (which will be in a DateTime type)?
I originally tried:
var test = context.MY_TABLE
.Include(x => x.MY_DETAILS)
.Where(x => startDate >= MyHelpers.ConvertDate(x.DATE_FIELD) &&
endDate <= MyHelpers.ConvertDate(x.DATE_FIELD))
.ToList();
I understand the error because linq can't generate the necessary sql statements from my method.
So how can I compare the dates with linq that are stored in the DB as a string?
To boot I won't know how the date will be stored in the string. For the time being I will assume '3/10/2016 12:30:00' will be the date string.
How big is the list? On .NET side the easiest way would be parsing the string into DateTime method and compare the results. But it is not possible to do that on Database side because EF cannot translate methods like DateTime.Parse or your MyHelpers.ConvertDate.
If your list is not very large (you must decide what "large" exactly means) you can "download all into .NET" and handle the data there. This can be done by calling ToList or ToArray before the first custom method is called.
var test = context.MY_TABLE
.Include(x => x.MY_DETAILS)
.ToList() // or .ToArray()
.Where(x => startDate >= MyHelpers.ConvertDate(x.DATE_FIELD) &&
endDate <= MyHelpers.ConvertDate(x.DATE_FIELD))
.ToList();
But this solution can be slow if you have a large result set and if you don't need the complete data it is pretty wasteful.
Another way I see is, not accessing the DbSet<T> but using a stored procedure. This procedure can parse the strings, compare them and return only what you really need.
SPs can be easily accessed in EF like the table data but the select-code is on database side written in SQL.
As mentioned by RIanGillis you can use ExecuteSqlCommand instead of a stored procedure too. This method takes an SQL string as an argument, so you can use any conversion method that is available in your database. It works similar to a stored procedure but the SQL statement would be stored in the .NET code.

How to Compare Only Date of dateTime objects in EF [duplicate]

_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();

The linq query taking too much time. Need to reduce the Time

Here i am using the below query and its taking lots of time around 14 to 15 seconds for retrieving the large amount of data.
In below Query the CreatedDate is of DateTimeOffset data type.
var naId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="NA").SalesPhaseId;
var rejectedId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="Rejected").SalesPhaseId;
var data = UnitOfWork.Leads.Query().AsEnumerable()
.Where(p =>(p.SalesPhaseId == naId || p.SalesPhaseId == rejectedId) &&
p.CreatedDate.Date >= fromDate && p.CreatedDate.Date <= toDate).Select(m =>
new
{
m.LeadId,
m.LeadOwnerId,
m.SalesPhaseId,
m.LeadActivities,
m.Employee,
m.SalesPhase,
m.CompanyName,
m.CreatedDate,
m.LeadHistories,
m.LeadAddresses
}).ToList();
I tried using the AsQueryable instead of the AsEnumerable but it gives the below error:
"The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."
Can you help me out to reduce the execution time of the query?
Your use of AsEnumerable is forcing the filtering to be done locally. It's pulling in all the data, then filtering it in your app. That's clearly very inefficient. Now, it seems that part of your query can't be directly expressed in LINQ to SQL. I see two options here.
Firstly you could do most of your filtering in SQL, but then do the date filtering locally:
var data = UnitOfWork.Leads.Query()
// Do this part of the query in SQL
.Where(p => p.SalesPhaseId == naId ||
p.SalesPhaseId == rejectedId)
.AsEnumerable()
// Do the rest of the query in-process
.Where(p => p.CreatedDate.Date >= fromDate &&
p.CreatedDate.Date <= toDate)
.Select(...)
That's suitable if the first part will filter it down massively, and then you only need to do local processing of a small set of data.
Alternatively, you could work out what your date filtering means in terms of DateTime. It looks like you could do:
// This may not be required, depending on the source.
fromDate = fromDate.Date;
// This will be, although you may be able to get rid of the ".Date" part.
toDate = toDate.Date.AddDays(1);
var data = UnitOfWork.Leads.Query()
// Do this part of the query in SQL
.Where(p => (p.SalesPhaseId == naId ||
p.SalesPhaseId == rejectedId) &&
p.CreatedDate >= fromDate &&
p.CreatedDate < toDate)
.Select(...)
That's created an equivalent query, but without using the Date property in the query itself.
Everything after AsEnumerable() is executed locally rather than on the server. See also
https://stackoverflow.com/a/2013876/141172
This means that all rows in the table are returned from the database, and then filtered in your C# code.
Remove that call so that the filtering happens server-side.
EDIT
Noticed Jon's comment and it reminded me that he reimplemented LINQ to Objects as a learning exercise. His comments about the AsEnumerable() reimplementation are worth reading
I can describe its behaviour pretty easily: it returns source.
That's all it does. There's no argument validation, it doesn't create another iterator. It just returns source.
You may well be wondering what the point is... and it's all about changing the compile-time type of the expression. I'm going to take about IQueryable in another post (although probably not implement anything related to it) but hopefully you're aware that it's usually used for "out of process" queries - most commonly in databases.
Now it's not entirely uncommon to want to perform some aspects of the query in the database, and then a bit more manipulation in .NET - particularly if there are aspects you basically can't implement in LINQ to SQL (or whatever provider you're using). For example, you may want to build a particular in-memory representation which isn't really amenable to the provider's model.
https://msmvps.com/blogs/jon_skeet/archive/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable.aspx
Your code should like this..
var naId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="NA").SalesPhaseId;
var rejectedId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="Rejected").SalesPhaseId;
var data = UnitOfWork.Leads.Query().AsQueryable()
.Where(p =>(p.SalesPhaseId == naId || p.SalesPhaseId == rejectedId) &&
p.CreatedDate>= fromDate.Date && p.CreatedDate <= toDate.Date).Select(m =>
new
{
m.LeadId,
m.LeadOwnerId,
m.SalesPhaseId,
m.LeadActivities,
m.Employee,
m.SalesPhase,
m.CompanyName,
m.CreatedDate,
m.LeadHistories,
m.LeadAddresses
}).ToList();
Firstly, You need to use .ToQueryable instead of .ToIEnumerable().
Secondly, you cannot use .Date to datetime properties inside a entity framework linq query. That only works for in-memory collections like list and arrays.

How to convert string to datetime and then get the lowest date

Records are coming from database and date is in the string format. I am using LINQ Min() query to select the record with lowest date. LINQ is not allowing me to use Convert.ToDateTime().
How can I get lowest date record?
You could do something like
.Min(ob => System.Convert.ToDateTime(ob.DateProperty));
This way the value gets converted before checking for the lowest value.
What do you mean by "linq is not allowing me Convert.ToDateTime()" ?
Can you not do:
DateTime minDate = listOfStrings.Select(x => Convert.ToDateTime(x)).Min();
..?
If the strings are not in a date/time format that is handled by Convert.ToDateTime(), you may need to look into DateTime.ParseExact() with an appropriate format string.
Edit: sorry, just realized another possibility. Do you mean that you cannot do the Convert.ToDateTime() because you are using LINQ against SQL and it is not usable within the expression? If so, try:
DateTime minDate = listOfStrings.ToList().Select(x => Convert.ToDateTime(x)).Min();
.. with a ToList() to force it to perform the query and then to the conversion.
there's a way of doing it by using the Orderby method in your LINQ request,
using a Func() on the (datetime)field you wish to order by, then selecting the first element.
It's not very clean as i would use a datetime in the database, but it should work.
Looking into some code samples would be useful. But this might help.
var minDateTime = strings.Min(s => DateTime.Parse(s));

How to Use Dates in Where Clause in EF Core?

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

Categories