If statements are conflicting with each other - how to recitfy - c#

I have two if statements and they both are conflicting with each other.
By default I can do filter by Dates and a Drop Down list from this if Statement:
DateTime fromDate = DateTime.MinValue;
DateTime toDate = DateTime.MaxValue;
if (dateFilter.Contains('~'))
{
fromDate = dateFilter.Split('~')[0] == "" ? DateTime.MinValue : Convert.ToDateTime(dateFilter.Split('~')[0]);
toDate = dateFilter.Split('~')[1] == "" ? DateTime.MaxValue : Convert.ToDateTime(dateFilter.Split('~')[1]);
}
filteredTracks = DataRepository.GetTracks()
.Where(c => (trackFilter == "" || c.TrackName.ToLower().Contains(trackFilter.ToLower()))
&&
(fromDate == DateTime.MinValue || fromDate < c.Date)
&&
(toDate == DateTime.MaxValue || c.Date < toDate)
);
but cannot do normal filtering records using this if statement, if the above one is being used:
if (!string.IsNullOrEmpty(param.sSearch))
{
var isTrackSearchable = Convert.ToBoolean(Request["bSearchable_1"]);
filteredTracks = DataRepository.GetTracks()
.Where(c => isTrackSearchable && c.TrackName.ToLower().Contains(param.sSearch.ToLower()));
}
else
{
filteredTracks = allTracks;
}
is it possible to have both of these to work?
Any help would be a great help :)

In such cases you can reuse the same query, conditionally adding Where clauses. E.g. for the second if-statement you can do just:
filteredTracks = filteredTracks.Where(...
Where filteredTracks already contains a result of first if-statement.

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

LINQ query is null

I am building a WinForms application that searches for books in the Database.
I have four tables:
Author,Book,Country,Genre;
There is a field in "Book" table called "Year".
I added startDate and endDate fields, so it can search for specific book released between the given two years(startDate and endDate both are integers). That is where my troubles began.
This is how I parse inputs.
int startDateResult = 0;
int? startDate = null;
if (inputStartDate == string.Empty)
{
startDate = null;
}
else
{
if (Int32.TryParse(inputStartDate, out startDateResult))
{
startDate = startDateResult;
}
else throw new Exception("Please input correct year");
}
int endDateResult = 0;
int? endDate = null;
if (inputEndDate == string.Empty)
{
endDate = null;
}
else
{
if (Int32.TryParse(inputEndDate, out endDateResult))
{
endDate = endDateResult;
}
else throw new Exception("Please input correct year");
}
This is the LINQ query I am using for searching.
specificBookForAuthor = _context.Books.Where(c =>
(c.Author.Name.Contains(First) || c.Author.Surname.Contains(Last))
&& book==string.Empty?true: c.Name.Contains(book)
&& country == string.Empty ? true : c.Author.Country.Name.Contains(country)
&& genre == string.Empty ? true : c.Genre.Name.Contains(genre)
&& inputYear == string.Empty ? true : c.Year==year
&& inputStartDate == string.Empty ? true : c.Year >= startDate
&& inputEndDate == string.Empty ? true : c.Year <= endDate
).Select(b => b).ToList();
This query did not work. Then, I tried to comment all the lines except "inputEndDate", typed 0 in startDate and 5000 in endDate. After Debug, found out, that "specificBookAuthor"-s count was 1. Which was CORRECT.
Commented Code :
specificBookForAuthor = _context.Books.Where(c =>
(c.Author.Name.Contains(First) || c.Author.Surname.Contains(Last))
//&& book==string.Empty?true: c.Name.Contains(book)
//&& country == string.Empty ? true :
// c.Author.Country.Name.Contains(country)
// && genre == string.Empty ? true : c.Genre.Name.Contains(genre)
// && inputYear == string.Empty ? true : c.Year==year
// && inputStartDate == string.Empty ? true : c.Year >= startDate
inputEndDate == string.Empty ? true : c.Year <= endDate
).Select(b => b).ToList();
Did the same with inputStartDate(commented inputEndDate line and uncommented inputStartDate). Worked fine.
I get the problem when I leave both of the fields uncommented. Like this:
specificBookForAuthor = _context.Books.Where(c =>
(c.Author.Name.Contains(First) || c.Author.Surname.Contains(Last))
//&& book==string.Empty?true: c.Name.Contains(book)
//&& country == string.Empty ? true :c.Author.Country.Name.Contains(country)
// && genre == string.Empty ? true : c.Genre.Name.Contains(genre)
// && inputYear == string.Empty ? true : c.Year==year
&& inputStartDate == string.Empty ? true : c.Year >= startDate
&& inputEndDate == string.Empty ? true : c.Year <= endDate
).Select(b => b).ToList();
In that case, "specificBookAuthor"-s count is NULL instead of 1.
Could you test the following change which may not be directly related to the issue, but it can give you a more readable/debugable code?
Rewrite your code to this:
specificBookForAuthor = _context.Books.Where(c =>
(c.Author.Name.Contains(First) || c.Author.Surname.Contains(Last)));
if(!string.IsNullOrEmpty(book))
specificBookForAuthor = specificBookForAuthor.Where(c => c.Name.Contains(book));
if(!string.IsNullOrEmpty(country))
specificBookForAuthor = specificBookForAuthor.Where(c => c.Author.Country.Name.Contains(country));
//....and so on with your other conditions;
//....finally:
specificBookForAuthor = specificBookForAuthor.ToList();
As I said, this may not resolve your problem, but this way you can properly debug condition by condition and maybe then you can find the problem.
So every Book has a property Year, representing the year in which a book was published.
Furthermore you have two nullable integers startDate and endDate and you want to limit the selected books to books published between startDate and endDate, with special cases if one or both of these values are null.
You have an input IQueryable<Book> and as output you want the query that will only fetch the books between startDate and endDate, with special treatment if these values are null.
To keep it readable, testable and maintainable, I suggest an extension function. See Extension Methods Demystified
public static IQueryable<Book> WherePublishedBetween(this IQueryable<Book> books,
Year? start,
Year? end)
{
if (start.HasValue)
{
if (end.HasValue)
return books.Where(book => start.Value <= book.Year && book.Year <= end.Value);
else
return books.Where(book => start.Value <= book.Year);
}
else
{ // no start value
if (end.HasValue)
return books.Where(book => book.Year <= end.Value);
else
return books;
}
}
Usage:
int? startYear = ...
int? endYear = ...
var queryBooks = myDbContext.Books
.Where(book => book.Author.Name.Contains(First)
|| book.Author.Surname.Contains(Last)
&& ... // check other properties)
.WherePublishedBetween(startYear, endYear)
// continue with the query, with whatever LINQ you need
.Select(book => ...)
The LINQ expression builder will be smart enough to combine these two Where statements using Expression.AndAlso

LINQ DateTime Query that ignores milliseconds

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

Linq to Sql get today date only data from db

i am unable to get the data from db with date only comparison. In Db InDateTime datatype is DateTime
using (HatronEntities context = new HatronEntities())
{
DateTime date = DateTime.Now.Date;
var AttendData = (from c in context.tbl_CoachMobAttendDetails
where c.CoachId == model.Id && c.InDateTime.Value.Date ==date
select c).FirstOrDefault();
}
using (HatronEntities context = new HatronEntities())
{
DateTime date = DateTime.Today;
DateTime until = date.AddDays(1);
var AttendData = (from c in context.tbl_CoachMobAttendDetails
where c.CoachId == model.Id &&
c.InDateTime.Value >= date &&
c.InDateTime.Value < until
select c).FirstOrDefault();
}
You didn't say initially that it was Linq To Entity Framework - but you say Linq To SQL! Then:
using (HatronEntities context = new HatronEntities())
{
DateTime date = DateTime.Today;
var AttendData = (from c in context.tbl_CoachMobAttendDetails
where c.CoachId == model.Id &&
DbFunctions.TruncateTime( c.InDateTime ) == date
select c).FirstOrDefault();
}
You can try like this:
c.InDateTime.Year == date.Year && c.InDateTime.Month == date.Month
&& c.InDateTime.Day == date.Day
or like
DbFunctions.TruncateTime(c.InDateTime.Value.Date) == date.Date
You can use DbFunctions.TruncateTime method:
DbFunctions.TruncateTime(c.InDateTime.Value.Date) == date.Date
Try Like this
c.InDateTime.Value.Date.Year == date.Year &&
c.InDateTime.Value.Date.Month == date.Month &&
c.InDateTime.Value.Date.Day == date.Day

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