Linq DateTime Operations Comparison - c#

So I have this statement
SearchResults = (from s in dbContext.tbl_ShippingProgram
where s.eta_date.Date > DateTime.Now.Date.AddMonths(-TimePeriod.Value)
select s).ToList();
Where SearchResults is defined as
public List<tbl_ShippingProgram> SearchResults { get; set; }
And where TimePeriod.Value is a int
I'm having difficulties figuring out why this doesn't work, there's nothing wrong the with just selecting all values since
SearchResults = (from s in dbContext.tbl_ShippingProgram
select s).ToList();
Works perfectly fine. Any and all help is appreciated <3
EDIT
- The issue is that it's not returning anything where it definately should be, checked the values in the db and the calculated DateTime.Now value and it should be returning something

Try DateTime.Now.AddMonths(-TimePeriod.Value).Date
I think you want the date portion of the datetime after the adjustment. This trips me up all the time too...
Couple of other things to try if this doesn't help:
Calculate the date outside of your linq statement (although you're not getting an unsupported error, but still).
Try using .Compare() for datetimes.
Do some sanity checking by using a hard-coded date that clearly encompass all results.

Related

How to efficiently search a list of objects with a DateTime property in my scenario

I have an already sorted list of object (sorted by date)
public class HistoryValue{
public DateTime Date {get;set;}
public decimal Value {get;set;
}
Then I have a list of days, for example,
1MonthAgo, 2MonthAgo,3MonthAgo,120MonthAgo
What I need is to find the Value on date
1MonthAgo, 2MonthAgo,3MonthAgo,120MonthAgo
If the date can not be found in the list, I should return the one just before that date. It is easiest to explain in a SQL statement although I am doing the real work in c#:
select top 1 Value
from HistoryValueList
where Date between #d12m-#lookbackdaymax and #d12m order by Date desc
I was thinking of using binary search, but don't think binary search will do exactly what I want. Maybe it is best do a looping and remember the closet object of each?
What you want is a "lower bound" kind of algorithm (please check this question), that is, a binary search (or bisect) algorithm that finds the left most element less than or equal to your search element.
You're in luck, there is such a thing called Language Integrated Query (LINQ) which lets you run queries on objects in C# which implement IEnumerable. That includes the List<HistoryValue> you're using.
You're looking for some code like:
HistoryValue val = historyValues.FirstOrDefault(v => v.Date > dateMin && v.Date <= dateMax);
Where historyValues is your list object.
This is pretty easy in C#. I am supposing that you get all records in list of HistoryValue class from DB!
Then you will write code like this:
List<HistoryValue> list = list; //your list get from db here!
HistoryValue historyValue = list.Where(m=>m.Date >= #12m && m.Date <= #lookbackdaymax ).First();

"Where" clause in linq to sql query using DateTime?

I'm trying to run a query of a table with the columns Domain, LastUsed, and FreqInHours In c#.
I just want to return all the Domains that I need to crawl.I find this out by checking the datetime that they were last Crawled (LastUsed) and how frequently they should be crawled (ex. every 6 hours). If the current date/time - the time it was last crawled is greater than the frequency I add want to return that domain.
Here is the current query I've written:
var query = (from c in context.SitemapFreqs
where (DateTime.Now - c.LastUsed).TotalHours > c.Freq
select c.domain);
Here is the exception I'm being given:
LINQ to Entities does not recognize the method 'System.DateTime ?
ToDateTime(System.Object)' method, and this method cannot be translated into a store expression.
Any help would be really appreciated.
You can use DbFunctions class and method DiffHours.
Here is an example:
var query = (from c in context.SitemapFreqs
where DbFunctions.DiffHours(DateTime.Now,c.LastUsed) > c.Freq
select c.domain);
Here is the documentation. Hope it helps.
Complex DateTime stuff is a bit much for Linq2SQL to handle.
If it's a relatively small amount of data, load it all into memory first:
var query = (from c in context.SitemapFreqs.ToList()
where (DateTime.Now - c.LastUsed).TotalHours > c.Freq
select c.domain);
If it's a larger amount of data, you can use DbFunctions, or provide the query yourself.
context.SitemapFreqs.SqlQuery("SELECT * from SitemapFreqs WHERE DATEDIFF('hour', GETDATE(), LastUsed) > Freq")
If you make sure the query returns the columns the SitemapFreqs object expects, it will map the objects just like it would anything else.
Looks like your c.LastUsed property is nullable. You can subtract nullable DateTimes using the c.LastUsed.Value property, but you should know that if it is null, this will throw an exception as you can't subtract a DateTime - null. I believe you have two options:
Change the property LastUsed in your class to a non-nullable DateTime by removing the ?.
Create a method inside of your class that determines if the DateTime? LastUsed is equal to null. If it is, return something where your LINQ query will ignore that value. (I.E: Set the value of LastUsed = DateTime.Now so that your LINQ query comes back as 0).
Hope this helps.

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

Linq to SQL DateTime2 query

I have a table with a datetime2 field and I need to get all rows out of it where the date is today. Rather oddly (in my opinion but I'm sure there's a valid reason for it) if I do:
MyTable.Where(t => t.Date == DateTime.Today).ToList()
it returns nothing even though there are entires with todays date.
What am I missing here? I thought that datetime2 allowed you to query like this instead of having to use greater than and less than to specify a timeframe?
Edit
I've tried using the .Date portion of the DateTime2 representation in Linq to SQL:
MyTable.Where(t => t.Date.Date == DateTime.Today).ToList()
but I'm still getting nothing. Yet in my database there are rows with the value 2011-08-05 00:00:00.0000000 which is clearly today.
Edit again
I've ran the query:
List<string> dates = MyTable.Select(t => t.Date.Date.ToString()).ToList();
and I'm getting results like 2011-08-05, so that portion obviously works.
However, when I run
DateTime.Today.Date.ToString()
I get 08/05/2011 00:00:00. Could the addition of this time portion be causing the issue? How would I remove this?
Edit 3
Got it to work using the code:
MyTable.Where(t => t.Date.Date.ToString() == DateTime.Today.Date.ToString("yyyy-dd-MM")).ToList();
This seems hacky though (converting to a string before comparison) and surely there must be a cleaner way?
It sounds like the date in the database isn't actually today (8th May). It's probably 5th August.
It looks like your datetime2 field is called Date. You need to use the Date property of this Date field to ignore the time of day.
MyTable.Where(t => t.Date.Date == DateTime.Today).ToList()

date difference in EF4

i need to get a difference of two dates ,one date from a table and one the current date, and the difference should be less than 9 0days. i need to use this as filter in where clause of the linq
i tried doing this
var list = from p in context.persons
where ((p.CreateDT).Subtract(DateTime.Now).Days < 90)
select p;
i get this excpetion :
LINQ to Entities does not recognize the method 'System.TimeSpan Subtract(System.DateTime)' method, and this method cannot be translated into a store expression.
I did research other articles but nothing helped..Any ideas
Trick here is that it can't translate all your fancy oo hoo-ha to plain old sql. Trick is to flip it on it's head:
var before = DateTime.Now.AddDays(-90);
var persons = context.Persons.Where(x => x.CreateDT > before);
EXPLANATION
Remember that everything in the WHERE bit of your LINQ statement must be translated from C# to SQL by the EF. It is very, very capable out of the box and handles most basic tasks, but it has no idea how to understand the most rudimentary method calls, such as DateTime.Subtract(). So the idea here is to let it do what it does best by precalculating a value and then passing that to the data tier.
The first line subtracts 90 days from the current time by adding negative 90 days. The second line passes it off to the database server.
The second line should translate to the SQL WHERE CreateDT > #BEFORETHIS
Update
It seems that EF doesn't support subtracting dates and returning a TimeSpan. Here's one way to solve the problem:
DateTime oldestDate = DateTime.Now.AddDays(-90);
var list = from p in context.persons
where p.CreateDT >= oldestDate
select p;
See this thread on Stackoverflow.
Try doing simply (p.CreateDate - DateTime.Now).Days < 90. Instead of calling DateTime.Subtract(). In some cases the operator overloads are implemented for Entity Framework even when the corresponding named methods are not.
If that doesn't work you could instead use ESQL or a stored procedure. As a final, dirty solution, you could call context.persons.ToList() and then call the DateTime.Subtract().

Categories