Manipulate DateTime using Linq - c#

I have a Solution table in the database and I want to display any solutions that is less than a day old as of now(DateTime.Now) Thank you
IQueryable<Solution> Solutions=
from x in db.Solutions
where x.Created_at == DateTime.Now -1
select x;

Use DateTime.AddDays to get target date. Then use >= comparison to filter solutions which are less old than target date (or equal to it):
IQueryable<Solution> Solutions =
from s in db.Solutions
where s.Created_at >= DateTime.Now.AddDays(-1)
select s;
NOTE: That will give you entities withing 24 hours from now. If you want to get entities from beginning of yesterday, then use DateTime.Today instead of DateTime.Now.

Related

LINQ query not statisfying the datetime validation

This is my LINQ for returning the matching record
var staffawards = await _context.StaffAwards.FirstOrDefaultAsync(c => c.StaffID == StaffAwards.StaffID && c.EmpID == StaffAwards.EmpID && c.AwardDate == StaffAwards.AwardDate);
The StaffAwards.AwardDate will be in this format "09/12/2020 12:00:00 AM"
whereas the AwardDate in my table will be like this "2020-12-09 17:16:00.000"
How can i convert the StaffAwards.AwardDate in Sql Server datetime?
AnyHelp would be appreciated.
If your code and your database use Date/DateTime types as they should be, and not strings then you need to understand a few things:
date datatypes don't have a format, only strings created from dates have a format. Whatever format you see in your code/sql query tool is the formatting it has applied when it showed you the date (it had to turn it to a string to display it)
a datetime with a time of midnight is a completely different datetime to one where the time is 17:16, just like a number 1.0 is a completely different number to 1.75352; you will never get a database to return you a record with a time of midnight if you use equals and pass a time of anything other than midnight, just like you will never succeed in getting a record where the age of the person is 1.0 by asking "where age = 1.75352"
Either fix up your parameter so it is midnight, like the db is, or use a parameter range (if the dates in the db will have times other than also)
//if the db date is always midnight
.Where(x => x.DateColumnInDb == datetimeParameter.Date);
//if the db might have times too
.Where(x => x.DateColumnInDb >= datetimeParameter.Date && x.DateColumnInDb < datetimeParameter.Date.AddDays(1));
By using a range, we do not risk asking the database to convert every datetime in the table, every time we want to query. Converting data in a where clause is typically a bad idea because it usually leads to significant performance loss because indexes cannot be used
Also, make sure your .net side datetime and your db time use the same timezone or they will actually be referring to different times
To use a Date with the Database-Format you can use the DbFunctions.
Like this:
var staffawards = await _context.StaffAwards.FirstOrDefaultAsync(c => c.StaffID == StaffAwards.StaffID && c.EmpID == StaffAwards.EmpID && DbFunctions.TruncateTime(DateTime.Parse(c.AwardDate)) == StaffAwards.AwardDate);
Important: For TruncateTime, you have to use a DateTime. You have to convert c.AwardDate to DateTime. DateTime.Parse(c.AwardDate)
Most likely, you have the SQL server installed on a separate machine, which may be due to a different date format.
But there is no need for this conversion, the entity framework will do it automatically for you.
If you just compare date, you can use this code :
var staffawards = await _context.StaffAwards.FirstOrDefaultAsync(c => c.StaffID == StaffAwards.StaffID && c.EmpID == StaffAwards.EmpID && c.AwardDate.Date == StaffAwards.AwardDate.Date);

Receiving Object reference not set to an instance of an object. on simple datetime retrieval from Raven

Not sure why its complaining about this error, but when comparing time stamps to DateTime.now I get a object reference error. Here is the simple code.
public class EmailTempKey
{
public string Id { get; set; }
public DateTime LastUpdated { get; set; }
public bool ShouldBeDisposed { get; set; }
}
//Linq Query to see if its been past 8 min
var emails = session.Query<EmailTempKey>().Where(x => DateTime.Now > x.LastUpdated.AddMinutes(8)).ToList();
If I remove the where clause it works, but obviously I need that. Thanks for any help
When you express a LINQ query, keep in mind that RavenDB has to translate that to Lucene before executing it. Therefore, you need to be thinking about how a particular field is being compared to the value you are passing in. You wrote:
Where(x => DateTime.Now > x.LastUpdated.AddMinutes(8))
Your LastUpdated field would need to be mutated for each record in order to resolve this query. This isn't something that Lucene or Raven can do. Just because you can express it in LINQ does not mean that it is valid for Raven. Instead, you could write:
Where(x => x.LastUpdated < DateTime.Now.AddMinutes(-8))
This is the algebraic equivalent to the query you specified, and should work, but there are still some problems.
You probably want an inclusive comparison, either <= or >=
The query will return items older than 8 minutes ago. I could be wrong, but I think you meant you wanted items newer than 8 minutes old, in which case you would flip the comparison:
Where(x => x.LastUpdated >= DateTime.Now.AddMinutes(-8))
Using DateTime.Now can be problematic. You are imposing the local time zone settings of the server onto your data. If your time zone uses daylight savings time, then twice a year you will get the wrong results from your query when your clocks transition. Even if you don't follow daylight savings time, you have a problem if you ever want to move your data somewhere else (like to the cloud, or an ISP). You should also read my post: The Case Against DateTime.Now. You should be storing your dates as UTC, or you can use DateTimeOffset - which works beautifully in RavenDB.
Perhaps you didn't realize, but RavenDB already keeps a Last-Modified value on every document in its metadata. You could use your own field if you want to, but why store it twice? You can query based on metadata with the Lucene syntax:
var results = session.Advanced.LuceneQuery<EmailTempKey>()
.WhereGreaterThan("#metadata.Last-Modified",
DateTime.UtcNow.AddMinutes(8));
If you want to stick with the LINQ syntax, you will need to define a static index instead.
I think this would fix it
Depending if the datetime LastUpdated may be null, choose one of the solutions below
May be null:
//Linq Query to see if its been past 8 min
var emails = session.Query<EmailTempKey>().Where(x => x.LastUpdated == DateTime.MinValue || (DateTime.Now > x.LastUpdated.AddMinutes(8)).ToList();
May not be null:
//Linq Query to see if its been past 8 min
var emails = session.Query<EmailTempKey>().Where(x => x.LastUpdated != DateTime.MinValue && (DateTime.Now > x.LastUpdated.AddMinutes(8)).ToList();

How to compare a string column(as DateTime) in LINQ?

I have a database with a ValidDate field - it's a string(we made a mistake, it should be a datetime, but we can't modify the database now.)
and now I want to compare this filed with a parameter(validDateStart) from the website:
priceList = priceList.Where(p => Convert.ToDateTime(p.ValidDate) >= Convert.ToDateTime(validDateStart));
var list = initPriceList.ToList();
But I get an error: The method ToDateTime is not implemented.
Can anybody give me some help? Thanks!
This is not supported in Linq to Entities (nor Linq to SQL to my knowledge). Remember that your query is executed on the database - where there is simply no equivalent for Convert.ToDateTime.
Any string parsing in your query would really just be a workaround - as a real solution make those columns not strings but datetime in the database and you would not have this problem in the first place.
A hacky workaround would be materializing all rows (you can use AsEnumerable() for that), then doing the parsing - this will have bad performance though but might work good enough if there are few rows:
var startDate = DateTime.Parse(validDateStart);
var list = priceList.AsEnumerable()
.Where(p => DateTime.Parse(p.ValidDate) >= startDate);
.ToList();
Edit:
With your example update it looks like you can just do string comparisons to do what you wanted - granted it's still a hack but would perform much better than materializing all rows. This is possible because your date format puts the most significant numbers first, then the less significant parts - it's year, then month, then day (should this not be the case and the day comes before the month in your example this solution will not work).
Assuming your input string validDateStart is in the same format as well you can just do:
var list = priceList.Where(p => p.ValidDate.CompareTo(validDateStart) >=0);
.ToList();
string comparison with String.CompareTo seems to be support both in Linq to Sql as well as Linq to Entities.
If all the records in your database always start with year, month and day (for example: the date format is yyyy-MM-dd HH:mm:ss or yyyy/MM/dd or yyyyMMdd) no matter if it has separators or not. The thing is that the values should has a format where it starts with year, month and day.
You can do the following:
1: Convert your filter value (website) to the same format as you have in your database:
// DateTime format in database: yyyy-MM-dd HH:mm:ss:ffffff
var from = filtro.CreationDateFrom?.ToString("yyyy-MM-dd");
var to = filtro.CreationDateTo?.AddDays(1).ToString("yyyy-MM-dd");
2: And write your query like this (using CompareTo method):
var query = (from x in ctx.TskTaskQueues
where x.CreationDatetime.CompareTo(from) >= 0
&& x.CreationDatetime.CompareTo(to) <= 0
select x);
It worked for me!
I'm not using LinqToEntities but I'm using LinqConnect (for Oracle) that is similar to LinqEntities.
If you use a format like this dd-MM-yyyy, it probably will not work.

Linq To SQL - compare two dates in two different formats

I'm trying to compare two dates that are in two different formats:
var messages = (from m in db.ChatMessages
where m.RoomID == roomID &&
m.MessageID > messageID &&
m.MessageTime > timeUserJoined.AddSeconds(1)
orderby m.MessageTime ascending
select new { m.MessageID, m.Text, m.User.username, m.MessageTime, m.Color });
My problem is that my Database tables stored DateTime fields in the US format i.e. 12/24/2011 1:35:11 PM. So in the query above, the line m.MessageTime > timeUserJoined.AddSeconds(1) might be 12/24/2011 1:35:11 PM > 24/12/2011 13:35:11 PM
How do I get around this - comparing two dates in two different formats and what are the best practices?
At the mment i'm not getting any records back, I think because of these comparison issues?
Many Thanks :)
You state they are DateTime fields... Then good news; DateTime in .NET and TSQL does not have any format - it is just a number. Any particular format you are seeing exists only in the imagination of your IDE or other tools (SSMS etc).
As long as it is DateTime you won't have a problem here.
First, I believe you should be using DateTime.CompareTo() to compare your timestamps.
Second, how are you consuming the messages collection? Are you aware that it's a collection of anonymous, untyped objects?
(I'd comment, but I don't have the rep)

LINQ to EF4 datetime comparison problems

I have a problem while comparing smalldatetime/datetime column value from DB(SQL Server 2008) with DateTime.Now in C#.
I know that datetime format in DB and on the server on which application is running are different, so I have done something like this to "cache" the results so date time comparison will be local and not be on server:
var inactiveAccounts = (from entry in ent.Accounts
where entry.Status == 0
select entry).ToArray();
var accountsFiltered = (from entry in inactiveAccounts
where entry.DeactivationDate < DateTime.Now
select entry).ToArray();
And at some pertiod of day I am not getting the right records.
I suspect it is due to where entry.DeactivationDate < DateTime.Now date comparison. And seems in EF it is tricky to work with datetime, please help me to identify the problem.
DonĀ“t know if it solves your problem but i would create a local variable and set DateTime.Now on it. Then use the local variable in your linq query.
This is done, because DateTime.Now gets evaluated in your query each time the where clause is called. So for each entry in inactiveAccounts you are working against another DateTime.
Also if you want to compare Dates without the Time value, you should use DateTime.Today
var inactiveAccounts = (from entry in ent.Accounts
where entry.Status == 0
select entry).ToArray();
DateTime currentDateTime = DateTime.Now;
var accountsFiltered = (from entry in inactiveAccounts
where entry.DeactivationDate < currentDateTime
select entry).ToArray();
You can use this directly:
var inactiveAccounts = (from entry in ent.Accounts
where entry.Status == 0 && entry.DeactivationDate < DateTime.Now
select entry).ToArray();
Because DataTime.Now and DateTime.UtcNow are translated as canonical functions = they should not be evaluated on .NET side but translated toGETDATE() or GETUTCDATE() SQL function calls respectively.
The rest of your question is unanswerable because providing information like
And at some period of day I am not getting the right records.
You must put much bigger effort to analysis of the problem if you want to get answer including which periods cause problem, what timezones are used, etc. Generally we will not help you with that because we don't see your data. It is also not a problem of EF because in your case it happends completely in linq-to-object = plain .NET code.

Categories

Resources