Wrong results fetching data based on date with Linq and SQL - c#

I am trying to get a list with some data from SQL using Linq. The results in list are based on date which the user inputs.
My code for getting the list
TimologioList = Dao.SearchTimologiaNotSendToMydata(apoDateEdit.DateTime,
eosDateEdit.DateTime.Date.AddDays(1).AddMilliseconds(-1),
MainDoc.Xrisi,
DefaultDiasafistis.DiasafistisDefault,
apestalmenaCheckEdit.Checked);
public List<Timologio> SearchTimologiaNotSendToMydata(DateTime apoDate, DateTime eosDate, string xrisi, Diasafistis diasafistis, bool apestalmenaTimologia)
{
List<Timologio> timologia = db.Timologio
.Where(p => (p.Imerominia >= apoDate && p.Imerominia <= eosDate)
&& (p.Xrisi == xrisi && p.Diasafistis == diasafistis)
&& (!p.IsYpodeigma.HasValue || !p.IsYpodeigma.Value)
&& p.ArithmosTimologiou != 0)
.OrderByDescending(p => p.Imerominia).ToList();
return timologia;
}
The two variables have values apoDate = 1/1/2022 12:00:00 and eosdate = 31/1/2022 11:59:59.
When I run this query, it returns another result which has a date of 1/2/2022 and I don't understand why.
Values of the date variables:
SQL data:
Results in the program:
I am using DateTime.Date.AddDays(1).AddMilliseconds(-1) because I found that it gives more precise values in the date

Related

Date and time between a date range in dotnet

I am facing the problem to know if DateTime is between a date range in the dotnet.
For example if the x.SchedulerStart value is 2022-11-02 06:46:30 and x.SchedulerEnd value is 2022-11-02 23:26:30. I want check this DateTime.Today value is inside the date range, but below coding is doesn't work. I have look at this StackOverflow question still cannot work How to know if a DateTime is between a DateRange in C#
Below is my coding:
x.SchedulerStart.Date >= DateTime.Today && x.SchedulerEnd.Date <= DateTime.Today
Whole code:
List<SAASMsgSchedulerForQueueList> msgSchedulerList = await _saasdbContext.SaMsgScheduler.AsNoTracking().Where(x => (x.Enabled == true && x.SchedulerStart.Date >= DateTime.Today && x.SchedulerEnd.Date <= DateTime.Today) &&
((x.SchedulerRecurring == "Daily" && x.RecurringTime == currentTime) || (x.SchedulerRecurring == "Weekly" && x.RecurringWeekday == weekDayNumber && x.RecurringTime == currentTime) ||
(x.SchedulerRecurring == "Monthly" && x.RecurringDay == currentDay && x.RecurringTime == currentTime) || (x.SchedulerRecurring == "Yearly" && x.RecurringMonth == currentMonth && x.RecurringTime == currentTime)))
.Join(_saasdbContext.TnMsgTemplate.AsNoTracking(),
schedule => schedule.TemplateId,
template => template.Id,
(schedule, template) => new { schedule, template })
.Join(_saasdbContext.SaMsgQuery.AsNoTracking(),
schedule => schedule.template.QueryId,
query => query.Id,
(schedule, query) => new SAASMsgSchedulerForQueueList()
{
ID = schedule.schedule.Id,
BranchID = schedule.schedule.BranchId,
TemplateID = schedule.schedule.TemplateId,
TemplateContent = schedule.template.TemplateContent,
Query = query.QuerySql,
MessageType = schedule.schedule.MessageType,
RecurringDatetime = schedule.schedule.RecurringDatetime,
}).ToListAsync();
Hope some one can guide me on how to solve this problems. Thanks.
You need to reverse the condition. Right now you're looking for something that started after today and ended before today.
It's better to write the query in a form that reflects what you want, ie Today is between the start and end dates :
x.SchedulerStart.Date <= DateTime.Today && DateTime.Today <= x.SchedulerEnd.Date
Better, as in after 20 years I still mix things up if I put the field on the left side of such a query. One shouldn't have to translate an expression to understand what it does
Another improvement is to avoid .Date. This results in a cast(ScheduleStart as date) in SQL Server. Normally such a cast would prevent the use of indexes. SQL Server is smart enough to convert this into a range query but can't use any indexes gathered for the ScheduleStart column and can still end up with an inefficient execution plan.
.Date can simply be removed from DateTime.Today <= x.SchedulerEnd.Date. If the end date is today, DateTime.Today <= x.SchedulerEnd holds no matter the time.
To eliminate .Date from the opening date, compare it to the next day, ie x.SchedulerStart < DateTime.Today.AddDays(1). If the start day is today, that will hold for every time. If SchedulerStart is on the next day, the condition will still be false.
A correct and efficient condition will be :
x.SchedulerStart < DateTime.Today.AddDays(1)
&& DateTime.Today <= x.SchedulerEnd
The query is targeting MySQL using Oracle's official EF Core provider, MySQL.EntityFrameworkCore, which has several known problems, which are fixed on Oracle's own schedule. That's why almost everyone uses the truly open source Pomelo.EntityFrameworkCore.MySql. Everyone as in 29.3M downloads for Pomelo vs 1.7M downloads for Oracle's provider.
In this case, Oracle's provider fails to treat DateTime.Today.AddDays(1) as a constant and tries to convert it to a SQL expression.
To avoid this problem, calculate the dates before the query, eg:
var today = DateTime.Today;
var tomorrow = today.AddDays(1);
...
x.SchedulerStart < tomorrow && today <= x.SchedulerEnd

LINQ Query to Convert numeric to datetime in where clause

I have a field with datatype numeric and I have stored hour values in it. Now I want to subtract the hours of a DateTime field with the numeric field and compare it with DateTime.Now() in a where clause of LINQ query. i'm using this logic `private List GetInterviewExamSlots(int programPreferenceId, string lookuptype)
{
var currentDateTime = DateTime.UtcNow;
var schedules = uow.RepositoryAsync<CoC_Schedule_Entry>()
.Queryable()
.AsNoTracking()
.OrderByDescending(x=> x.Start_Datetime)
.Where(x => x.Capacity != null &&
x.Capacity != 0 &&
(x.Start_Datetime).AddHours((double)- x.Event_Registration_Deadline) > currentDateTime &&
x.Fully_Booked_Flag != Constants.YesFlag &&
x.CoC_Schedule_Entry_Type.Schedule_Entry_Type_Code.Equals(lookuptype) &&
x.CoC_Lookup3.Hidden_Value.Equals(LookupCodes.OpenHiddenValue)
&& (x.Program_Preference_ID == programPreferenceId
||
x.Program_Preference_ID == null))
.Select(x => new ............`
but it throws an exception LINQ to Entities does not recognize the method '.AddHours' method and this method cannot be translated into a store expression.
Not everything, that can be expressed in C# can be translated to the store's language. What this is, depends on the specific store and the LINQ provider (like e. g. entity framework for sqlserver). In your case the provider can't translate the AddHours function call.
To get past this you can
remove the method call from your query, convert the result to something that can be queried via Linq2Objects (e. g. by adding .ToList() to convert your (intermediate) result to a List<...>) and then query it again. Now that nothing needs to be translated, AddHours (and any other function call) will work.
Depending on your data this might consume many local resources.
var preSelectedSchedules = uow.RepositoryAsync<CoC_Schedule_Entry>()
.Queryable()
.AsNoTracking()
.OrderByDescending(x=> x.Start_Datetime)
.Where(x => x.Capacity != 0
&& x.Fully_Booked_Flag != Constants.YesFlag
&& x.CoC_Schedule_Entry_Type.Schedule_Entry_Type_Code.Equals(lookuptype)
&& x.CoC_Lookup3.Hidden_Value.Equals(LookupCodes.OpenHiddenValue)
&& (x.Program_Preference_ID == programPreferenceId
|| x.Program_Preference_ID == null))
.ToList();
var schedules = preSelectedSchedules
.Where(x => x.Start_Datetime.AddHours(-x.Event_Registration_Deadline) > currentDateTime)
.Select(...);
provide a query in the store's language (like a view if we're talking about sql) which returns the desired data and you use this a the data source of your query.
If you have very few different values for x.Event_Registration_Deadline, you can also try another approach:
select all distinct values for x.Event_Registration_Deadline
for each value calculate var theshold = currentDateTime.AddHours(<value>);
perform the query with .Where(x => x.Start_Datetime > threshold)

Getting a full month report after searching a date in LINQ

I need to generate a full month report base on some criteria. The first condition is- I am taking a anonyms Date from user and after checking all the condition it will generate full month report.
I tried to generate the report but this is returning a day wise report. Everything is fine except the month. Please help me to do this.
[HttpGet("inner-join/{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult GetReport(DateTime id)
{
try
{
IEnumerable<BTBPending> objBTBPendingList = _unitOfWork.BTBPending.GetAll(includeProperties: "ProformaInvoice,ContractList,SupplierList,CountryList,ItemList,BuyerList,StyleList,TradeTermList,ErpRemarksList,StatusList,LcNoList,UdAmendList");
IEnumerable<ProformaInvoice> objProformaInvoiceList = _unitOfWork.ProformaInvoice.GetAll(includeProperties: "ActualContract,ContractList,SupplierList,CountryList,ItemList,BuyerList,StyleList,TradeTermList");
var query = objBTBPendingList
.Where(x => x.LcOpenDate == id)
.Where(x => x.CountryListId == 26)
.Where(x => x.StatusListId == 12 || x.StatusListId == 13 || x.StatusListId == 14)
.Join(objProformaInvoiceList,
btbPending => btbPending.ContractListId,
pi => pi.ContractListId,
(btbPending, pi) => new
{
LcNo = btbPending.LcNoList,
Value = btbPending.PiValue,
ContractNo = pi.ContractList,
Buyer = pi.BuyerList,
PiNo = pi.PINo,
Supplier = pi.SupplierList,
Item = pi.ItemList
}).ToList();
return Ok(query);
}
catch (Exception ex)
{
return StatusCode(500, "Internal Server Error, Please Try Again Leter!");
}
}
You have to make condition for the month, you are doing on the date. so do like this.
.Where(x => x.LcOpenDate.Month == id.Month && x.LcOpenDate.Year == id.Year)
Here I am assuming both id and LcOpenDate are from the same timezones.
As per the comment, LcOpenDate is DateTime?, so you need to do this.
LcOpenDate.Value.Month and LcOpenDate.Value.Year
DateTime gives your a full date and time and looks something like
2022-11-11 11:44:53 PM
What is likely going on is that when you are storing the data in the database, you are ommitting the time. Something like this:
var date = new DateTime(now.Year, now.Month, now.Day)
// 2022-11-11 12:00:00 AM
This is the only way x.LcOpenDate == id would work. Otherwise it would only return items with the open date at the exact time you provided up to the millisecond.
Try this instead:
.Where(x => x.LcOpenDate.Year == id.Year && x.LcOpenDate.Month == id.Month)
Additionally, if you are on .net 6+ you can use DateOnly and TimeOnly

ASP.NET MVC Filtering results by date returns 0 results

I am trying to filter the results of a database query by date. The user will input a date value as a string and then I use that string to compare to the date of every query result to try to find a match, however there is never a match, even when I know one exists.
Query and filtering:
var documents = from s in db.Documents
select s;
if (!String.IsNullOrEmpty(searchString))
{
documents = documents.Where(s => s.Order_Date.ToString().Contains(searchString) ||
s.Comment.Contains(searchString));
}
It should be noted that if the searchString is found in the Comment column, then it works fine. But again, there is never a match for date.
In the SQL table that the app connects to the column Order_Date is of date datatype (not datetime). However in the model Order_Date is a DateTime variable because as far as I'm aware C# does not have just date.
Here is an example of the problem:
Result
What am I doing wrong?
You are comparing 11/8/2004 with s.Order_Date.ToString(). This approach has several problems:
Maybe s.Order_Date contains 2004-08-11 but when you do s.Order_Date.ToString() it turns to month-day-year date format 8/11/2004 (instead day-month-year) and 8/11/2004 != 11/8/2004
What happens if user enters 11/08/2004 ? 11/08/2004 != 11/8/2004. User will don't understand why they are no results.
If you want to search by date the best solution is to use a date entry control. If for your UX is important to enter date in a text control instead a date control then you should to tokenize text and try to identify dates on text, convert to date and use a date to compare on linq expression.
DateTime? search_date_start = tokenize_and_extract_date_start(searchString)
DateTime? search_date_end = tokenize_and_extract_date_end(searchString)
String? search_comment = remove_dates_from_search_string(searchString)
documents =
documents
.Where(s =>
search_date_start == null ||
s.Order_Date >= search_date_start)
)
.Where(s =>
search_date_end == null ||
s.Order_Date <= search_date_end)
)
.Where(s =>
search_comment == null ||
s.Comment.Contains(search_comment)
);
I figured it out using Jonathan's comment. This is the simplest way to do it:
if (!String.IsNullOrEmpty(searchString))
{
try
{
var test = DateTime.Parse(searchString);
documents = documents.Where(s => s.Order_Date == test);
}
catch (FormatException e)
{
documents = documents.Where(s => s.Comment.Contains(searchString));
}
}

C# LINQ Datetime in a String Value

I have a database with a string column that indicates a datetime value with this format: yyyyMMdd.
For example the value 20160908 indicate the 08 of Semptember 2016.
I have two datetimepicker for filter dateFrom and dateTo value. I take the datetime value in my datepicker textbox with this simply code:
DateTime dataFromSel = Convert.ToDateTime(txtDatFrom.Text);
DateTime dataToSel = Convert.ToDateTime(txtDatTo.Text);
My query is:
var query = from c in snd.WineOWines.OrderByDescending(x => x.DDT_DATA)
select new
{
c.ID,
c.VABRMA,
c.VABNCL,
c.DDT_DATA,
};
If I have a datetime filter i add this code:
if (txtDatDa.Text != "")
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
int dataDa = Convert.ToInt32(dataDaSel);
query = query.Where(x => int.Parse(x.DDT_DATA) >= dataDa);
}
The problem is that i can't to list the query before the filter because i have a lot of rows and if i use this query i can't do an int.parse in the LINQ statement.
How can i write a LINQ statement that select the row in my DB with datetime between from and to, if the value in the column is a string?For now my query works fine, but i need a where clause for this problem.
Thanks to all
If dates have the same format you do not need to cast them to int.
You should be able to compare stings and remove the cast...
if (!string.IsNullOrEmpty(txtDatDa.Text))
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
var res = query.Where(x => string.Compare(dataDaSel, x.Name) <= 0);
}
Linq to SQL supports string.Compare(string, string) as described here
https://social.msdn.microsoft.com/Forums/en-US/98180ae0-4ccd-4ecd-89d5-576a04169219/linq-to-entities-with-string-comparison?forum=adodotnetentityframework
You don't have to put int.Parse, you can do a direct string comparison it is going to work ok. Neither you have to convert your dataDaSel into integer.
if (txtDatDa.Text != "")
{
string dataDaSel = Convert.ToDateTime(txtDatDa.Text).ToString("yyyyMMdd");
query = query.Where(x => x.DDT_DATA >= dataDaSel);
}
E.g.
"20120201" >= "20120201" // true
"20120101" >= "20120201" // false
"20120301" >= "20120201" // true
As long as you keep format as yyyyMMdd it is going to work ok even with string.

Categories

Resources