LINQ to entites does not recognize Convert.ToDatetime method - c#

EDIT All the other answers that link to a previous question's wont work for me because they are either using two tables or they know what startdate they are looking for.
I have the following LINQ query where i am trying to get the data from a table for the last 14 days. LINQ does not recognize Convert.ToDatetime method. The Query_Date column is a type string and i can't change it. How do i get the data i need?
var logs = (from bwl in db.UserActivities
where Convert.ToDateTime(bwl.Query_Date) >= DateTime.Now.AddDays(-14)
select new
{
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();

So i couldn't get what i wanted because i would have to make too many changes so the workaround i am doing is: I am using this code
var logs = db.UserActivities.ToList().Take(100);
This will get me the last 100 entries. I will give options for more or less entries then they can filter it on date in the search bar on the datatable.
It's not great but time is against me and this will suffice.

Do you have data being entered at least every day? If so, what about something like this:
var oldestDate = DateTime.Now.AddDays(-14);
var dateString = oldestDate.ToString(*/ your date format */);
var oldestID = db.UserActivities.First(b => b.Query_Date == dateString).Id;
var logs = (from bwl in db.UserActivities
where bwl.Id > oldestID
select new {
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();
Basically you find a record on that date and use its ID as a proxy for the date. This only works in certain circumstances (i.e. if the IDs are in date order).
This also isn't guaranteed to be the oldest entry on that date, but that could be achieved either by using ID order:
var oldestID = db.UserActivities.Where(b => b.Query_Date == dateString)
.OrderBy(b => b.Id)
.First().Id;
Or more lazily by using -15 instead of -14 when you add days, if you don't mind grabbing an unknown percentage of that 15th day.

Convert.ToDateTime works if your Query_Date has proper format. If not, check your string expression is convertable format.
I tested below code and it works fine when I assume Query_Date is a form of DateTime.toString().
var logs = (from bwl in db.UserActivities
where DateTime.Now - Convert.ToDateTime(bwl.Query_Date) <= TimeSpan.FromDays(14)
select new
{
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();
I also tested with your where expression Convert.ToDateTime(bwl.Query_Date) >= DateTime.Now.AddDays(-14) and confirmed that it gives same result.

Related

How to group by records from database based on date (day) c#?

I know this could be a possible duplicate question, pardon me if it is.
Is there a way to GroupBy all the records from the database by date?
So:
say i have multiple records for this date 22/05/2022
and say i have multiple records from this date: 23/05/2022
Can i group all the records based on date parameter 22/05 and 23/05?
So that i would end up with a list containing n list for each day.
Here is what i did:
var grpQuery = await ctx.Registration.GroupBy(c => c.DateReference.Day).ToListAsync();
Where:
Registration is my table from where i am pulling the data
DateReference is a Date object containing the date
But i am getting this error "the linq expession could not be translated".
Can somone give me some advice on this?
EDIT
I tried this but it seems not to load any data, even setting break a break point will not return anything:
var grpQuery = await query.GroupBy(d => new { DateReference = d.DateReference.Date }).Select(c => new RegistrationViewModel()
{
RegistrationId = c.FirstOrDefault().RegistrationId,
PeopleId = c.FirstOrDefault().PeopleId,
DateReference = c.Key.DateReference,
DateChange = c.FirstOrDefault().DateChange,
UserRef = c.FirstOrDefault().UserRef,
CommissionId = c.FirstOrDefault().CommissionId,
ActivityId = c.FirstOrDefault().ActivityId,
MinuteWorked = c.FirstOrDefault().MinuteWorked,
}).OrderBy(d => d.DateReference).ToListAsync();
Where:
RegistrationViewModel contains all those properties including DateReference
If i call the method using the API is stuck at "pending"
First, don't. Even if the query was fixed, the equivalent query in the database would be GROUP BY DATEPART(day,registration.Date) which can't use indexes and therefore is slow.
According to the docs the equivalent of DATEPART(day, #dateTime) is dateTime.Day. The query still needs to have a proper Select though.
A correct query would be :
counts = ctx.Registrations.GroupBy(r=>r.RegistrationDate.Day)
.Select(g=>new {Day=g.Key,Count=g.Count())
.ToList();
The equivalent, slow query would be
SELECT DATEPART(day,registration.Date) as Day,count(*)
FROM Registrations
GROUP BY DATEPART(day,registration.Date)
Things get worse if we have to eg filter by date. The query would have to scan the entire table because it wouldn't be able to use any indexes covering the Date column
SELECT DATEPART(day,registration.Date) as Day,count(*)
FROM Registrations
WHERE Date >'20220901'
GROUP BY DATEPART(day,registration.Date)
Imagine having to scan 10 years of registrations only to get the current month.
This is a reporting query. For date related reports, using a prepopulated Calendar table can make the query infinitely easier.
SELECT Calendar.Day,COUNT(*)
FROM Registrations r
INNER JOIN Calendar on r.RegistrationDate=Calendar.Date
GROUP BY Calendar.Day
or
SELECT Calendar.Year, Calendar.Semester, Calendar.Day,COUNT(*)
FROM Registrations r
INNER JOIN Calendar on r.RegistrationDate=Calendar.Date
WHERE Calendar.Year = #someYear
GROUP BY Calendar.Year, Calendar.Semester,Calendar.Day
A Calendar table or Date dimension is a table with prepopulated dates, years, months, semesters or any other reporting period along with their names or anything needed to make reporting easier. Such a table can contain eg 10 or 20 years of data without taking a lot of space. To speed up queries, the columns can be aggressively indexed without taking too much extra space.
Doing the same in EF Core requires mapping Calendar as an entity and performing the JOIN in LINQ. This is one of the cases where it makes no sense to add a relation between entities :
var query=from registration in ctx.Registrations
join date in Calendar
on registration.Date equals Calendar.Date
group registration by date.Day into g
select new { Day=g.Key, Count=g.Count()};
var counts = query.ToList();
If you are using EF Core Please try this:
var grpQuery = await ctx.Registration.Select(a=>new {Re = a, G = (EF.Functions.DateDiffDay(a.End,DateTime.Today))}).ToListAsync().ContinueWith(d=>d.Result.GroupBy(a=>a.G));

Read most recently inserted rows by Date using linq to Entity framework

I have a log table in my db and wants to fetch only those records which are added most recently based on the column name RowCreateDate, this is how I am trying to achieve the records which is bringing the rows from the db but I feel may be there is a better way to achieve the same.
using (var context = new DbEntities())
{
// get date
var latestDate = context.Logs.Max(o => o.RowCreateDate);
if(latestDate!=null)
{
lastDate = new DateTime(latestDate.Value.Year, latestDate.Value.Month, latestDate.Value.Day,00,00,00);
logs = context.Logs.Where( o.RowCreateDate >= lastDate).ToList();
}
}
What i need to know I am doing right or there would another better way?
Yet another option:
context.Logs.Where(c => DbFunctions.TruncateTime(c.RowCreateDate) == DbFunctions.TruncateTime(context.Logs.Max(o => o.RowCreateDate)))
This reads explicitly like what you want (get all rows with date equals max date) and will also result in one query (not two as you might have expected).
You can't simplify this code because LINQ to Entities does not support TakeWhile method.
You can use
using (var context = new DbEntities())
{
// get date
var latestDate = context.Logs.Max(o => o.RowCreateDate);
if(latestDate!=null)
{
lastDate = new DateTime(latestDate.Value.Year, latestDate.Value.Month, latestDate.Value.Day,00,00,00);
logs = context.Logs
.OrderBy(o => o.RowCreateDate)
.AsEnumerable()
.TakeWhile(o => o.RowCreateDate >= lastDate);
}
}
BUT it takes all your data from DB, which is not very good and I do not recommend it.
I think this will do (if we assume you want to get top 3 most recent record):
var topDates = context.Logs.OrderByDescending(x=>x.RowCreateDate).Take(3)
First, I think that your code is fine. I don't see the problem with the two queries. But if you want to simplify it you use TruncateTime, like this:
IGrouping<DateTime?, Logs> log =
context.Logs.GroupBy(x => DbFunctions.TruncateTime(x.RowCreateDate))
.OrderByDescending(x => x.Key).FirstOrDefault();
It will return a grouped result with the logs created during the last day for RowCreateDate.

LINQ Query against Azure table service fails

I have a few records saved in my Azure Table Storage. I'm trying to pull records from a table,for only a particular day/date, for the currently logged in user.
My query returns nothing, so my list is always empty, even though I know that I have 3 records for this month, in my table.
I'm not sure why the query fails in this case. How do I pull records for a specific date, for a specific user? Any help?
This is what I've tried so far:
public async Task<Result<List<Alert>>> FetchAlertsForDate (DateTime date)
{
try {
var fromDate = new DateTime(date.Year,date.Month,date.Day,0,0,0); //lets create a 12:00:00 AM date
var toDate = new DateTime(date.Year,date.Month,date.Day,23,59,59); //lets create a 23:59:59PM date
var alertTable=client.GetSyncTable<Alert>();
var alerts = await alertTable.Where(n=>n.AccountId==client.CurrentUser.UserId).Where(n=> n.StartDate >= fromDate && n.StartDate <= toDate).ToListAsync();
return Result<List<Alert>>.Success(alerts);
} catch (Exception ex) {
return Result<List<Alert>>.Failure (ex.Message + ex.StackTrace);
}
}
The code you have written contains no obvious bugs to answer your question
How do I pull records for a specific date, for a specific user?
Rather than a date range you use in your method you can just compare the date part of a dateTime like this;
var alerts = await alertTable.Where(n=>n.AccountId==client.CurrentUser.UserId).Where(n=> n.StartDate.Date == date.Date).ToListAsync();
I think you can do away with the second where clause too;
var alerts = await alertTable.Where(n=>n.AccountId==client.CurrentUser.UserId && n.StartDate.Date == date.Date).ToListAsync();
If you are not getting any records then for that specific combination of userId and Date then the most likely thing is that there aren't any records with that exact combination.
For some reason, the same query ended up working. I improved on it by removing the first part, where I was checking for the current user's id. That wasn't necessary since in my case.
So the final query looks like this:
var alerts = await alertTable.Where(n=> n.StartDate >= fromDate && n.StartDate <= toDate).ToListAsync();
This now pulls up all the logged in user's details.

Date Difference Logic in LINQ

I'm attempting to access data from two different database tables and then join them together on two fields using LINQ in C#. I believe that I have a logically sound overall working approach. Part of the problem I'm running into is that I'm filtering the data from both tables prior to joining them, because the tables have far too much data and it would cause a crash.
The main problem is that for one of the tables I need to pull only data that has a timestamp (column) value of today. The timestamp value is of type System.DateTime?.
I've tried a few different ways:
DateTime? currentDate = System.DateTime.Now;
var second_data = (from b in this.database.table
where EntityFunctions.DiffDays(b.timeStamp.Value, currentDate) == 0
select b);
I'm under the impression this doesn't work because there's no function in the database to handle it. Inner Exception: '{"FUNCTION database.DiffDays does not exist"}'
var second_data = (from b in this.database.table
where b => b.timeStamp.Value.Date == DateTime.Now.Date
select b);
This doesn't work because 'The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.'
var second_data =
this.database.table.Where(sd => sd.timeStamp.Value.Date == DateTime.Now.Date);
But this again fails because of the use of .Date.
Unfortunately, because I don't have the memory to hold all that data, the possibility of of pulling all the data first and then running date logic on it is out of the question. If anyone could give any insight on how I might be able to solve this problem it would be greatly appreciated, thank you.
To get rows from the table that are only for today (or a specific date range), you could simply do this. The nice thing about this approach is that it works for both cases of a specific date or a date range.
// specify date range (without time)
DateTime currentDate = System.DateTime.Now.Date;
DateTime nextDate = currentDate.AddDays(1);
var second_data = from b in this.database.table
where b.timeStamp.Value >= currentDate
and b.timeStamp.Value < nextDate
select b;
query = query.Where(c=> DbFunctions.DiffDays(c.ToDate, DateTime.Now) < 30);
Its not working in my scenario
I'm using Sql Server and I get your first method to work if I remove the call to timestamp.Value. I don't think your version compiles because DiffDays takes nullable DateTimes for both parameters.
DateTime? currentDate = System.DateTime.Now;
var second_data = (from b in this.database.table
where EntityFunctions.DiffDays(b.timeStamp, currentDate) == 0
select b);
The other thing I note is that I get a warning:
'System.Data.Entity.Core.Objects.EntityFunctions' is obsolete: 'This
class has been replaced by System.Data.Entity.DbFunctions.'
So if it still doesn't work in MySql you could try DbFunctions instead
this answer helped me for the exact day number, not in-between difference:
Found it on forums.asp.net
Here's a sample showing one way to get all employees with a DOB between now and 14 days from now...
var employeesWithBirthday =
from emp in dc.Employees
let BirthdayDiff = (new DateTime(DateTime.Now.Year, emp.BirthDate.Month, emp.BirthDate.Day) - DateTime.Now).TotalDays
where BirthdayDiff >= 0 && BirthdayDiff <= 14
select emp
;
...although, be aware that a query like that will do a table scan (can't use any indexes)...

Linq 2 Sql DateTime format to string yyyy-MM-dd

Basically, i need the equivalent of T-SQL CONVERT(NVARCHAR(10), datevalue, 126)
I've tried:
from t in ctx.table
select t.Date.ToString("yyyy-MM-dd")
but it throws not supported exception
from t in ctx.table
select "" + t.Date.Year + "-" + t.Date.Month + "-" + t.Date.Day
but i don't think it's an usable solution, because i might need to be able to change the format.
The only option I see is to use Convert.ToString(t.Date, FormatProvider), but i need a format provider, and I'm not sure it works either
FormatProvider doesn't work, String.Format doesn't work (string.Format("{0:yyyy-MM-dd}", t.Date) throws not supported exception too).
In case someone else has this problem, I solved this problem by creating a seperate function to do the date formatting for me.
My Linq looks something like this:
from a in context.table
where ...
select new Class
{
DateString = GetFormattedString(a.DateTimeObject)
}
And GetFormattedString just returns DateTimeObject.ToString("yyyy-MM-dd");
This works for me!
Assuming that t.Date is nullable (DateTime?) this could be the problem, try using:
from t in ctx.table select (t.HasValue ? t.Date.Value.ToString("yyyy-MM-dd") : string.Empty );
Edit: Second try
The problem is the translation to SQL; it tries to translate the .ToString() to an SQL representation, and fails. So if you should do the following it should work:
(from t in ctx.table select t.Date).ToList().Select(d => d.ToString("yyyy-MM-dd"))
Or
(from t in ctx.table select t.Date).AsEnumerable().Select(d => d.ToString("yyyy-MM-dd"))
AsEnumerable() transforms the previously used IQueryable into an IEnumerable, thus stopping the generation of the SQL (in case of Linq to SQL) or any other transfromation by the provider implementing the specific IQueryable (e.g. Linq to SQL Provider).
Note, before calling AsEnumerable() you should have completed any actions that you want to be converted to SQL and executed on the database directly.
Is there a reason to perform the conversion on the database side? Whenever I run into this type of situation, I tend to just allow the database to give me the raw data and then do the massaging and manipulation within the application. Depending on the volume of requests to the database server and the size of the result set, I don't want to tie up processing and response time doing data conversions that can be handled by the client.
look no.3
var user = (from u in users
select new
{
name = u.name,
birthday = u.birthday.Value
})
.ToList()
.Select(x => new User()
{
name = x.name,
birthday = x.birthday.ToString("yyyyMMdd") // 0埋めされるよ
});
Try to create an object class that you can set the properties and let the properties be the value for your view.. Set the datetime data from LINQ as string and not datetime.. ex.
//Property class
[DataContract()]
public class Info
{
[DataMember(Name = "created_date")]
public string CreateDate;
}
//Controller
var date = from p in dbContext.Person select p;
CreateDate = Convert.ToDateTime(p.create_date).ToString("yyyy-MM-dd");
Hope you'll try this.. I have this on my past applications and this is what I did.
I had a global search function on a quoting website from which I wanted to be able to search on all details of a quote (quote references, vehicle details, customer details etc.) including the created dates using only the single input text value:
This means that I definitely don't want to enumerate the results before attempting to cast the date to the appropriate string format.
In an attempt to do this, I've come up with the following:
// this is obviously only a fragment of my actual query
_context.Quotes
.Where(q => string.Concat(
q.DateCreatedUtc.Day < 10 ? "0" : "",
q.DateCreatedUtc.Day,
"/",
q.DateCreatedUtc.Month < 10 ? "0" : "",
q.DateCreatedUtc.Month,
"/",
q.DateCreatedUtc.Year
)
.Contains(searchTerm));
I can confirm this translates to a database operation using EF Core V5 and Pomelo V5 with a MySql database.
The generated SQL looks something like this:
WHERE
LOCATE(#search_term, CONCAT(
CASE WHEN EXTRACT(DAY FROM `quote`.`date_created_utc`) < 10 THEN '0' ELSE '' END,
CAST(EXTRACT(DAY FROM `quote`.`date_created_utc`) AS CHAR),
'/',
CASE WHEN EXTRACT(MONTH FROM `quote`.`date_created_utc`) < 10 THEN '0' ELSE '' END,
CAST(EXTRACT(MONTH FROM `quote`.`date_created_utc`) AS CHAR),
'/',
CAST(EXTRACT(YEAR FROM `quote`.`date_created_utc`) AS CHAR)
)) > 0
This entire query has turned into a bit of a Frankenstein though and I am seriously questioning the value of allowing users to search on the dates.
try this
var select = from s in db.Table
where s.date == someDate
select new
{
date = DateTime.Parse(s.date.ToString()).ToString("yyyy-MM-dd"),
};

Categories

Resources