LINQ DateTime Query that ignores milliseconds - c#

x.CreateDate DateTime is stored in our database down to milliseconds. My dateTimePicker values startdate and enddate only allows for querying down to seconds.
How can change my query to ignore the milliseconds of x.CreateDate? I thought the code I wrote below would work but it is not.
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.AddMilliseconds(-x.CreateDate.Millisecond) == startdate)
.OrderByDescending(x => x.ID)
.Take(count);

var query = from l in _context.Logs
where l.ApplicationID == applicationId
&& SqlMethods.DateDiffSecond(l.CreateDate,startdate) == 0
orderby l.ID descending
select l).Take(count);
This avoids converting every date in you table into a string and the subsequent string comparison, by comparing the two dates as dates.

Getting CreateDate and startdate in the same format will help you compare apples to apples. This should accomplish that.
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.ToString(#"MM/DD/YYYY h:mm:ss") == startdate.ToString(#"MM/DD/YYYY h:mm:ss")
.OrderByDescending(x => x.ID)
.Take(count);

I have no idea why I could not get any results from the queries posted above as I tried several variations of their themes. However I did get it working correctly by adding milliseconds to the startdate and enddate variables and it s working.
if (stardDateIsValid && endDateIsValid)
startdate = startdate.AddMilliseconds(000);
enddate = enddate.AddMilliseconds(999);
query = _context.Logs.Where(x => x.ApplicationID == applicationId && x.CreateDate >= startdate && x.CreateDate <= enddate).OrderByDescending(x => x.ID).Take(count);

You can create extension method.
public const long TicksPerMillisecond = 10000;
public const long TicksPerSecond = TicksPerMillisecond * 1000;
public static bool IsEqualIgnoreMilliseconds(this DateTime date, DateTime compareDate)
{
long tickDiff = date.Ticks - compareDate.Ticks;
return tickDiff > 0 ? tickDiff < TicksPerSecond : tickDiff < -TicksPerSecond;
}
Then you can use this:
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.IsEqualIgnoreMilliseconds(startdate)
.OrderByDescending(x => x.ID)
.Take(count);

Related

How to filter only when date is not null using optional condition

I am a little confused about how I can use the date as an optional condition.
if there is a date then <= of date, if the date is null then don't filter based on date.
My code is like this
DateTime date= DateTime.UtcNow.AddDays(-10);
foreach (var camEvent in dbContext
.CAM_EVENTS
.Where(c => c.USER_ID == userID &&
c.CAM_ID == cam.CAM_ID &&
c.EVENT_DATE >= date) // I want to change this like
.OrderByDescending(c => c.DATE))
{...}
I want that line to look something like this
(date && c.EVENT_DATE >= date)
so it only filter when date is not null, but this is not working.
I'd do the following logic:
(date==null || (c.EVENT_DATE >= date))
You can do something like this:
DateTime date = DateTime.UtcNow.AddDays(-10);
var filteredContext = dbContext
.CAM_EVENTS
.Where(c => c.USER_ID == userID &&
c.CAM_ID == cam.CAM_ID)
.OrderByDescending(c => c.DATE);
if (date != null) {
filteredContext = filteredContext.Where(c.EVENT_DATE >= date);
}
foreach (var camEvent in filteredContext) {
...
}
You can use a ternary operator, also known as a conditional operator.
foreach (var camEvent in dbContext
.CAM_EVENTS
.Where(c => c.USER_ID == userID &&
c.CAM_ID == cam.CAM_ID &&
// if date is not null, it will return bool c.EVENT_DATE >= date, otherwise just true
(date != null ? c.EVENT_DATE >= date : true))
.OrderByDescending(c => c.DATE))

How to efficiently grab results from Linq with or without user input params

I have a linq query that I would like to return results with user input data. However, if this function gets called and there is zero data from user, OR user just wants to search via data, OR just one of the other parameters, how can I efficiently write the linq to accommodate for this? Here is the Linq and function:
public static List<Objects.Logs.GenericLog> GetLogs(int entityId, int logLevelId,
DateTime startDate, DateTime endDate)
{
var logsList = new List<Objects.Logs.GenericLog>();
using(var db = CORAContext.GetCORAContext())
{
logsList = (from i in db.GenericLog select new Objects.Logs.GenericLog()
{
EntityId = i.FkEntityId,
LogSourceCode = i.FkLogSourceCode,
LogLevelId = i.FkLogLevelId,
LogDateTime = i.LogDateTime,
LogId = i.PkLogId,
Message = i.Message
})
.Where(i => i.LogDateTime >= startDate && i.LogDateTime <= endDate)
.Where(i => i.EntityId == entityId || i.EntityId == null)
.Where(i => i.LogLevelId == logLevelId || i.EntityId == null)
.ToList();
}
return logsList;
}
For example, in the second and third Where(), I have || i.EntityId == null... thinking this would accomodate for is user input for Entity is null?
Will this work?
Also, how can I do this for date ranges? Can I also do the same?
Finally, is there a BETTER way to do this?
Split creating a query and generating a final result by .ToList()
When you generate a query, you can add where statements on demand, like this:
public static List<Objects.Logs.GenericLog> GetLogs(int entityId, int logLevelId, DateTime startDate, DateTime endDate)
{
var logsList = new List<Objects.Logs.GenericLog>();
using(var db = CORAContext.GetCORAContext())
{
var query = (from i in db.GenericLog select new Objects.Logs.GenericLog()
{
EntityId = i.FkEntityId,
LogSourceCode = i.FkLogSourceCode,
LogLevelId = i.FkLogLevelId,
LogDateTime = i.LogDateTime,
LogId = i.PkLogId,
Message = i.Message
});
if(someCondition) {
query = query.Where(i => i.LogDateTime >= startDate && i.LogDateTime <= endDate)
}
query = query.Where(i => i.EntityId == entityId || i.EntityId == null)
query = query.Where(i => i.LogLevelId == logLevelId || i.EntityId == null)
logsList = query.ToList();
}
return logsList;
}
If I understand you correctly, you have a method that gets a filtered set of data based on the values of the parameters passed in. But you want to make the parameters optional, so if the user wants data for all entities, they wouldn't pass in an entityId.
If that's the case, then you can make the arguments optional by providing a default value for them in the method signature. We can then check if the argument has the default value, and if it does, don't apply that filter; otherwise apply it.
We can do this by doing .Where(x => argHasDefaultValue || someFilter). This works because if the argument has the default value, then the second part of the || is ignored.
For example:
public static List<Objects.Logs.GenericLog> GetLogs(int entityId = int.MinValue,
int logLevelId = int.MinValue, DateTime startDate = default(DateTime),
DateTime endDate = default(DateTime))
{
using(var db = CORAContext.GetCORAContext())
{
return db.GenericLog
.Where(i => startDate == default(DateTime) || i.LogDateTime >= startDate)
.Where(i => endDate == default(DateTime) || i.LogDateTime <= endDate)
.Where(i => entityId == int.MinValue || i.EntityId == entityId)
.Where(i => logLevelId == int.MinValue || i.LogLevelId == logLevelId)
.Select(i => new Objects.Logs.GenericLog
{
EntityId = i.FkEntityId,
LogSourceCode = i.FkLogSourceCode,
LogLevelId = i.FkLogLevelId,
LogDateTime = i.LogDateTime,
LogId = i.PkLogId,
Message = i.Message
}).ToList();
}
}

Changing my stored procedure to Linq

I have a question regarding how to convert the following to linq. I've been trying to get my head around ASP.NET MVC, and one of the biggest hurdles for me is Linq.
CREATE PROCEDURE [dbo].[SelectAvailableCoops]
#startDate DATETIME, #endDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT ID, coopName, coopCPN
FROM tbl_Coops
WHERE ID NOT IN (SELECT coopID
FROM tbl_bookings
WHERE (startDate <= #startDate AND endDate >= #startDate)
OR (startDate < #endDate AND endDate >= #endDate)
OR (#startDate <= startDate AND #endDate >= endDate)
)
END
GO
If it helps, at the moment I have the following in my action result.
BookingsListVM bookinglist = new BookingsListVM();
//bookinglist.Customers = db.Customers.ToList();
bookinglist.Customers = (from c in db.Customers select c).ToList();
bookinglist.CustomerBookings = (from cb in db.CustomerBookings select cb).ToList();
bookinglist.Coops = (from co in db.Coops select co).ToList();
Well here is one
db.Customers.Where(x=> db.CustomerBookings.Any(a=> a.coopID != x.Id &&
((a.StartDate <= startDate && a.EndDate >= enddate)
||
(a.StartDate < endDate && a.EndDate >= enddate)
||
(a.StartDate <= startDate && a.EndDate >= endDate)
)));
The other answer looks better but here is a slightly longer solution that is hopefully a bit easier to understand.
//Returns IDs
var bookingIds = tbl_bookings
.Where(b => b.ReleaseDate <= startDate && b.ReleaseDate >= endDate
|| (b.ReleaseDate < endDate && b.ReleaseDate >= endDate)
|| (b.ReleaseDate <= startDate && b.ReleaseDate >= endDate))
.Select(b => b.Id);
//Returns anonymous object list containing all records
//with an ID not found in previous result set
var bookings = tbl_bookings.Where(b => !bookingIds.Contains(b.Id))
.Select(b => new { ID = b.Id, CoopName = b.Id, coopCPN = b.Id })
.ToList();

Entity framework "Select date time from string"

I need to select the records from a table for date interval.
But the date to select from is kept as nvarchar in this pattern
20160511_155015 (yyyymmdd_hhmmss)
I cannot use ToList() to make it as DateTime.ParseExact(entry.StartDate, "yyyyMMdd_HHmmss", CultureInfo.InvariantCulture)
The table keeps several millions records.
So I need to make something like this:
var preQuery = context.Table
.AsNoTracking()
.Select(x => new
{
StartDate = ConvertFrom()),
Mode = x.Mode,
SessionStart = x.AStart,
SessionEnd = x.AEnd,
x.SensorNumber
})
.Where(x => x.StartDate != null
&& x.StartDate >= startDate
&& x.StartDate <= endDate)
.ToList();
Is it possible to convert the string representation to Datetime and then proceed with Where clause ?
Please try this DateTime.ParseExact(dateTime ,format,CultureInfo.InvariantCulture);
var preQuery = context.Table.AsNoTracking().Select(x => new
{
StartDate = ConvertFrom(),
Mode = x.Mode,
SessionStart = DateTime.ParseExact(x.AStart,"yyyyMMdd_HHmmss", CultureInfo.InvariantCulture),
SessionEnd = DateTime.ParseExact(x.AEnd,"yyyyMMdd_HHmmss", CultureInfo.InvariantCulture),
x.SensorNumber
})
.Where(x => x.StartDate != null && x.StartDate >= startDate && x.StartDate <= endDate)
.ToList();
You can try:
StartDate.StartsWith("20160511") or so..
or
Convert.ToInt32(StartDate.Substring(0,8)) > 20160511
by the way, i think you might want to run a script, as long as it takes, and create a new column which will generate a DateTime based on that column

how to pass optional parameter in linq where condition

I have a action in MVC controller
public ActionResult ExportExcel(string ReportType,DateTime? FromDate,DateTime? ToDate)
{
var query = UnitOfWork.RepoTestResAnalysis.GetAll();
var QueryData = query.Where(s => s.MSO == ms && (FromDate != null && (s.TEST_DATE.Value >= FromDate)) && (ToDate!=null && (s.TEST_DATE.Value<=ToDate))).ToList();
}
Now If FromDate and ToDate are null then I am getting QueryData Count is Zero. But I need all records. So Can anyone tell me how can I get expected result. While FromDate & ToDate has value then I am getting expected result.
According to the information you have provided
Change you below statement:
var QueryData = query.Where(s => s.MSO == ms && (FromDate != null && (s.TEST_DATE.Value >= FromDate)) && (ToDate!=null && (s.TEST_DATE.Value<=ToDate))).ToList();
To
var QueryData = query.Where(s => s.MSO == ms && (FromDate == null || (s.TEST_DATE.Value >= FromDate)) && (ToDate == null || (s.TEST_DATE.Value<=ToDate))).ToList();
If the FromDate Or ToDate will be equal to NULL, it won't check them against s.TEST_DATE.Value.
You can do it like below also:
Change QueryData assignment to:
var QueryData = query.Where(s => s.MSO == ms &&
(s.TEST_DATE.Value >= (FromDate ?? DateTime.MinValue)) &&
(s.TEST_DATE.Value <= (ToDate ?? DateTime.MaxValue))).ToList();
I know it's an old question, but I will be glad if my code can help anybody.
I think following implementation will be the short and easy to read:
public ActionResult SomeMethod(string ReportType, DateTime? FromDate, DateTime? ToDate)
{
var query = UnitOfWork.RepoTestResAnalysis.GetAll();
var QueryData = query.Where(x => x.DateField >= (FromDate ?? x.DateField) && x.DateField <= (ToDate ?? x.DateField).ToList();
}

Categories