Date Difference Logic in LINQ - c#

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

Related

LINQ to entites does not recognize Convert.ToDatetime method

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.

Linq if DateTime field is older than X hours

I have tried the following (obviously without the //), but I can't get any to work, can anybody help please?
public void CleanBasket()
{
//double validHours = 3;
// var expired = (from a in db.Baskets where (DateTime.Now - a.DateCreated).TotalHours > validHours select a);
//var expired = (from a in db.Baskets where (DateTime.Now.Subtract(a.DateCreated).Hours > 3) select a);
//var expired = (from a in db.Baskets where(a => a.DateCreated > DateTime.Now.AddHours(-1));
//foreach (Basket basket in expired) db.DeleteObject(expired);
db.SaveChanges();
}
In this case surely you can simply do your date time calculation before you invoke LINQ:
double validHours = 3;
var latest = DateTime.UtcNow.AddHours(-validHours);
var expired = (from a in db.Baskets where a.DateCreated < latest select a);
For any more complex DateTime operations that you need to do in the database and cannot do this way you can use SqlFunctions.
BTW you should store your times in Utc not local time. Calculations using DateTime.Now will be wrong during daylight savings time changes.
My guess is that linq-to-entities doesn't know how formulate the query with the DateTime.Now operation. To do this, I would get the values in a list and then with just linq, filter them out.
public void CleanBasket()
{
var cutoff = DateTime.Now.Subtract(new TimeSpan(3, 0, 0));
var baskets = db.Baskets.Where(a=>a.DateCreated<cutoff);
db.DeleteObjects(baskets); // You can combine this with the last line
db.SaveChanges();
}
It is very likely that a ORM wont be able to translate TimeSpan operations, check this question it could be helpful: Comparing dates in query using LINQ
basically you can consider that if the method you are using does not have a literal translation to SQL it is very likely that it will not be supported.

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"),
};

How do I perform Date Comparison in EF query?

Please help.
I am trying to figure out how to use DATE or DATETIME for comparison in a linq query.
Example:
If I wanted all Employee names for those who started before today, I would do something like this in SQL:
SELECT EmployeeNameColumn
FROM EmployeeTable
WHERE StartDateColumn.Date <= GETDATE() //Today
But what about linq?
DateTime startDT = //Today
var EmployeeName =
from e in db.employee
where e.StartDateColumn <= startDT
The above WHERE doesn't work:
Exception Details: System.NotSupportedException: The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Use the class DbFunctions for trimming the time portion.
using System.Data.Entity;
var bla = (from log in context.Contacts
where DbFunctions.TruncateTime(log.ModifiedDate)
== DbFunctions.TruncateTime(today.Date)
select log).FirstOrDefault();
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/84d4e18b-7545-419b-9826-53ff1a0e2a62/
That should work. Are you sure that there isn't another part of the query that triggered the exception? I have several instances of queries of the form
var query = from e in db.MyTable
where e.AsOfDate <= DateTime.Now.Date
select e;
in my code.
It may be due to the date in the database being nullable. Try this:
var EmployeeName =
from e in db.employee
where e.StartDateColumn.Value <= startDT
You can check the condition like this
var nextDay = DateTime.Today.AddDays(1);
var query = from e in db.MyTable
where e.AsOfDate >= DateTime.Today && e.AsOfDate < nextDay
select e;
here you'll get the records on AsOfDate date as we checking between today(00:00:00) and tommorow(00:00:00) we'll get today's date record only what ever may be the time...
You can not use .Date
If you would like to check for today you can create a datetime with no time
DateTime myDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
var e = (from mds in myEntities.Table
where mds.CreateDateTime >= myDate
select mds).FirstOrDefault();
try this:
DateTime dd = DateTime.Parse("08/13/2010 00:00:00");
var data = from n in ContributionEligibilities
where n.ModifiedDateTime.Date >= DateTime.Parse("08/13/2010").Date
select n;
data.Dump("Result") ;
I'm curious to the error message saying 'Date', when you're passing a 'DateTime'. Could it be that 'StartDateColumn' is actually a 'Date', rather than a 'DateTime' in the database? That might mess up the comparison...
use a local variable to store the Date value and then use that variable in the query:
DateTime today = DateTime.Now.Date;
from scheme in context.schemes
where scheme.EndDate > today
select scheme
I am using a LinqDataSource and I had problems getting my query with a Date Comparison in it to execute without errors. The answer is to use the WhereAddParameters function and add the test value as a strongly typed parameter.
See the example below where I am matching a groupid and checking to see if the StopDate in my record is greater that or equal to a Date/Time stamp of now.
I am using this code fragment currently and it works like a charm.
LinqCampaigns.WhereParameters.Add("StopDate", System.Data.DbType.Date, DateTime.Now.ToString())
LinqCampaigns.Where = "GroupId = " & myGrp & " && " & "StopDate >= #StopDate"
Works like a charm....
.Date did not work, but .Day did for me.
var query = from o in Payments
where o.Order.OrderDate.Day != o.PaymentDate.Day
orderby o.Order.OrderDate
select new
{
o.Order.OrderID,
o.Order.OrderDate,
o.PaymentDate,
o.Order.FirstName,
o.Order.LastName,
o.Order.CustomerID
};
query.Dump();
ensure that you check null value like this :
'(from mm in _db.Calls
where mm.Professionnal.ID.Equals(proid)
&& mm.ComposedDate.HasValue &&
(mm.ComposedDate.Value >= datemin) && (mm.ComposedDate.Value <= date)
select mm).ToArray();'

Looking for Specific Date

Anyone know how to query for a specific date within entity framework ? I tried following code, but it gives me NotSupportedException.
var deposit = (from tempDeposit in entities.Deposit
where !tempDeposit.IsApproved
&& tempDeposit.CreatedDate.Date == DateTime.Today
select tempDeposit).FirstOrDefault();
I also tried following code but still gave me NotSupportedException.
var deposit = (from tempDeposit in entities.Deposit
where !tempDeposit.IsApproved
&& tempDeposit.CreatedDate.ToFullString() == DateTime.Today.ToFullString()
select tempDeposit).FirstOrDefault();
ToFullString() is an extension method
public static string ToFullString(this DateTime date){
return date.ToString("yyyyMMdd");
}
Please help.
Try this:
var d1 = DateTime.Today;
var d2 = d1.AddDays(1);
var deposit = (from tempDeposit in entities.Deposit
where !tempDeposit.IsApproved
&& tempDeposit.CreatedDate >= d1
&& tempDeposit.CreatedDate < d2
select tempDeposit).FirstOrDefault();
Since you can't use the .Date property of a DateTime column, since that would have to be written in SQL with a range of converts, casts, truncates, etc. then you need to compare the whole DateTime value, date and time both, to a value, and thus you need to compare to a range.
Edit Changed to reflect that .AddDays isn't supported.
Well, after sometime tried, I found the solution
var deposit = entities1.Deposit
.Where("CreatedDate >= #0 and CreatedDate < #1", DateTime.Today, DateTime.Today.AddDays(1))
.FirstOrDefault();

Categories

Resources