linq where statement with OR - c#

I'm using linq-to-sql for a query like this:
public static List<MyModel> GetData(int TheUserID, DateTime TheDate)
using (MyDataContext TheDC = new MyDataContext())
{
var TheOutput = from a in TheDC.MyTable
where a.UserID == TheUserID
(where a.Date1.Month == TheDate.Month && where a.Date1.Year == TheDate.Year)
OR
(where a.Date2.Month == TheDate.Month && where a.Date2.Year == TheDate.Year)
group a by a.Date1.Date AND by a.Date2.Date into daygroups
select new MyModel{...};
How do I write this to make the OR and the AND statement work? I've tried putting a || and a && in place but it doesn't work and I'm stuck on this query.
Basically, it should return a list of days within a month and in the MyModel, I do counts. For instance, in a column I count the number of appointments set on a given day and in another column I count the number of appointments attended on the same day. Date1 refers to the date the appointments are set and Date2 refers to the dates the appointments are attended. So for example, on March 3rd 2011, I've set 4 appointments (Date1 is 3/11/2011 for these) and they're set for various dates in the future (Date2). During the same date (March 3rd is Date2 this time), I've also attended several other appointments that were set on other dates in the past.
Thanks for any suggestions.

using (MyDataContext TheDC = new MylDataContext())
{
var TheOutput = from a in TheDC.MyTable
where a.UserID == TheUserID &&
(a.Date1.Month == TheDate.Month && a.Date1.Year == TheDate.Year)
||
( a.Date2.Month == TheDate.Month && a.Date2.Year == TheDate.Year)
group a by a.Date1.Date AND by a.Date2.Date into daygroups
select new MyModel{...};
Try removing the 4 extra "where" and change the OR to ||.

Related

Comparison of Date From SQL Server and C# DateTime

I have a DateTime column in a SQL Server database. The data stored as follows:
2020-10-04 23:45:00.527
I tried to compare the date as follows with current date (Date in database should be less than current date)
DateTime today = DateTime.Now.Date;
var result = (from c in TableName
where (c.Email == email) &&
c.Password == password && c.Status == 1 &&
c.ValidTill.Date <= today
select c).ToList();
But unfortunately I get this exception
'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported
Even tried the below method, that doesn't seem to work:
DbFunctions.TruncateTime(c.ValidTill)
My comparison would be like this -
2020-10-04 23:45:00 (Datetime in database) <= 2020-10-10 23:00:00 (current date & time)
You don't need .Date
c.ValidTill <= today
or comparing only with date
EntityFunctions.TruncateTime(x.ValidTill) <= today.Date
needs to do the work.
var today = DateTime.Now;
var result = (from c in TableName
where (c.Email == email) &&
c.Password == password && c.Status == 1 &&
c.ValidTill <= today
select c).ToList();
hope it will work.

Linq simple query improvement

I'm a beginner in Linq queries and I'm wondering if my query can be improved one way ore another:
long vehid = json.VehicleId.Value;
DateTime date = DateTime.Parse(json.date.Value);
var Alerts = (from t2 in entities.Alerts.AsNoTracking()
where
t2.GeneratedTimeLocal.Year == date.Year
&& t2.GeneratedTimeLocal.Month == date.Month
&& t2.GeneratedTimeLocal.Day == date.Day
&& (t2.AlertType == 2 || t2.AlertType == 3)
&& t2.vId == vid
select new
{
GeneratedTimeLocal = t2.GeneratedTimeLocal,
OptionalText = t2.OptionalText
});
return Alerts;
The problem is that the Alerts datatable has a huge amount of data in it that increases day by day and right now it's kind of slow.
The GeneratedTimeLocal field from Alerts datatable is type datetimeoffset(7).
Is there a way to improve this query?
Define a date range to improve the query. Then check the query execution plan and based on that decide if you need a new index or change existing indexes.
long vehid = json.VehicleId.Value;
DateTime dateFrom = DateTime.Parse(json.date.Value).Date; // date with no time
DateTime dateTo = dateFrom.AddDays(1); // add one day to create the date range
var Alerts = (from t2 in entities.Alerts.AsNoTracking()
where
t2.GeneratedTimeLocal >= dateFrom
&& t2.GeneratedTimeLocal <= dateTo
&& (t2.AlertType == 2 || t2.AlertType == 3)
&& t2.vId == vid
select new
{
GeneratedTimeLocal = t2.GeneratedTimeLocal,
OptionalText = t2.OptionalText
});
return Alerts;
On the other hand, remember that this query won't be executed until you do a ToList(), for example.
Try this index:
CREATE INDEX IX_Alert_GeneratedTimeLocal_vId_AlertType_with_include ON Alert(GeneratedTimeLocal, vId, AlertType) INCLUDE(OptionalText)
I'm assuming you're using SQL Server. You could also try a filtered index if the table is huge. Check out this link: https://learn.microsoft.com/en-us/sql/relational-databases/indexes/create-filtered-indexes

Get the last entry in database of two different dates and calculate the difference

I have a table that records information from an inverter roughly every 15 minutes. One of the pieces of data that the inverter sends is the kwhtotal which is a number that represents how much total power has been generated through that inverter. I am trying to get the query right for getting the power generated for a particular day. To do that I need to retrieve the last reading on the prior day and compare it to the last reading on the current day.
Here is what I have so far:
DateTime prevStartD = new DateTime((utcStartingDate.AddDays(i - 1)).Year, (utcStartingDate.AddDays(i - 1)).Month, (utcStartingDate.AddDays(i - 1)).Day, 0, 0, 0);
DateTime prevEndD = new DateTime((utcStartingDate.AddDays(i - 1)).Year, (utcStartingDate.AddDays(i - 1)).Month, (utcStartingDate.AddDays(i - 1)).Day, 23, 59, 59);
var previousDay = (from s in db.PowerInverterHistorys
join u in db.PowerInverters on s.inverter_id equals u.id
where u.name == record && (s.recordTime >= prevStartD && s.recordTime <= prevEndD)
orderby s.recordTime descending
select new
{
s.recordTime,
s.kwhtotal
}).Take(1);
DateTime currStartD = new DateTime((utcStartingDate.AddDays(i)).Year, (utcStartingDate.AddDays(i)).Month, (utcStartingDate.AddDays(i)).Day, 0, 0, 0);
DateTime currEndD = new DateTime((utcStartingDate.AddDays(i)).Year, (utcStartingDate.AddDays(i)).Month, (utcStartingDate.AddDays(i)).Day, 23, 59, 59);
var currentDay = (from s in db.PowerInverterHistorys
join u in db.PowerInverters on s.inverter_id equals u.id
where u.name == record && (s.recordTime >= currStartD && s.recordTime <= currEndD)
orderby s.recordTime descending
select new
{
s.recordTime,
s.kwhtotal
}).Take(1);
double? pDay = 0, cDay = 0;
foreach (var p in previousDay) { pDay = p.kwhtotal; }
foreach (var c in currentDay) { cDay = c.kwhtotal; }
var generatedPower = cDay - pDay;
It works and runs, however it is inefficient. It take far to long for the page to open when ran. Is there anything I can do to speed up this query? All I need to do is subtract the kwhtotal of the last entry in the previous day from the kwhtotal of the last entry in the current day.
Could you combine the two queries into one, with the restriction s.recordTime >= prevStartD && s.recordTime <= currEndD and without the Take(1). This will mean only one trip to the database instead of two. Once you have the data set back you can query those results locally using the s.recordTime <= prevEndD condition to find your pDay value, then query again with the s.recordTime >= currStartD condition and look to the last record to get the cDay value.
var previousDay = (from s in db.PowerInverterHistorys
join u in db.PowerInverters on s.inverter_id equals u.id
where u.name == record && (s.recordTime >= prevStartD && s.recordTime <= prevEndD)
orderby s.recordTime descending
select new
{
s.recordTime,
s.kwhtotal
}).Take(1);
OrderBy is expensive operation for the DB if u have large dataset. Use Max() or Min() instead that will give u corresponding first row all the time.
THis should also apply to your "CurrentDay" query.

How to get all records within the last Two Days from the current Date using EF 4?

EF 4 in C#.
I have my query, at the moment I'm able to filter the result by the current Date (just date not considering TIME).
I need to filter the result FROM the last two days TO the current Date (no idea how to do it).
I tried in my query currenteDate - 2 but without success.
Could you please give me an example? Thanks for your time on this.
DateTime currenteDate = DateTime.UtcNow.Date;
var contents = from cnt in context.CmsContents
where cnt.IsPublished == true & cnt.IsDeleted == false & cnt.Date == currenteDate
orderby cnt.ContentId descending
select new { cnt.ContentId, cnt.Title, cnt.TitleUrl, cnt.Date, cnt.TypeContent };
For changing current date you need use currenteDate.AddDays(-2). And use >= instead of == to get all records from 2 days before and till the last record
DateTime currenteDate = DateTime.UtcNow.Date.AddDays(-2);
var contents = from cnt in context.CmsContents
where cnt.IsPublished == true & cnt.IsDeleted == false & cnt.Date >= currenteDate
orderby cnt.ContentId descending
select new { cnt.ContentId, cnt.Title, cnt.TitleUrl, cnt.Date, cnt.TypeContent };
use the compare method from the DateTime-object:
cnt.Date.CompareTo( DateTime.Now.AddDays( -2 ) ) >= 0

c# sorting list <DateTime> and inserting to database

I´ve come to a total stop with my program and im in need of some help.
I got an xml file with customer billings and billing dates. This file has about 4000 billing dates. What i want is to sort them so the once that is in a range of a period date of 2010-04-01 - 2011-03-31 adds to a table column named period1. And the other dates goes to period2 that is 2011-04-01 - 2012-03-31.
Ive been testing and testing this solution in diffrent ways but it wont work. Im adding all the dats to a list named dates. And trying:
if (dates.All(date => date >= startDatePeriod1 && date <= stopDatePeriod1))
{
adapterBonus.InsertPeriod1Query(// insert to database));
}
else if (dates.All(date => date >= startDatePeriod2 && date >= stopDatePeriod2))
{
adapterBonus.InsertPeriod2Query(// insert to database));
}
startDatePeriod1 = 2010-04-01
stopDatePeriiod1 = 2011-03-31
and so on
The Enumerable.All extension method returns true if every element in the sequence verifies the condition. If dates contains dates in both periods, none of the ifs will run, because both calls to Enumerable.All will return false.
I'm not sure what you mean by "adds to a table column named period1", but if you mean to count all the dates in each period, use Enumerable.Count:
int period1Count = dates.Count(date => date >= startDatePeriod1 && date <= stopDatePeriod1);
int period2Count = dates.Count(date => date >= startDatePeriod2 && date <= stopDatePeriod2);
adapterBonus.InsertPeriod1Query(period1Count);
adapterBonus.InsertPeriod2Query(period2Count);
What you are doing, is the following:
Check whether ALL dates are in period one. If so, insert them into period 1 in the database. If not, check whether ALL dates are in period two and insert them into period 2 in the database.
You want to do the following:
foreach (var period1Date in dates.Where(date => date >= startDatePeriod1 &&
date <= stopDatePeriod1))
{
adapterBonus.InsertPeriod1Query(// insert period1Date to database));
}
foreach (var period2Date in dates.Where(date => date >= startDatePeriod2 &&
date <= stopDatePeriod2))
{
adapterBonus.InsertPeriod2Query(// insert period2Date to database));
}
BTW: I fixed an error in your second condition. It should be date <= stopDatePeriod2 instead of date >= stopDatePeriod2!
All return a boolean specifying whether all elements satisfy a condition. What you need is a Where() to extract those you need.
Something like:
adapterBonus.InsertPeriod1Query(dates.Where(date => date >= startDatePeriod1 && date <= stopDatePeriod1));
adapterBonus.InsertPeriod2Query(dates.Where(date => date >= startDatePeriod2 && date <= stopDatePeriod2));
Try this:
var period1Dates = dates.Where(date => date >= startDatePeriod1 && date <= stopDatePeriod1);
var period2Dates = dates.Where(date => date >= startDatePeriod2 && date >= stopDatePeriod2);
foreach(var date in period1Dates)
{ adapterBonus.InsertPeriod1Query(// insert to database)); }
etc.
easiest way to do this is doing a
startDatePeriod1 = 2010-04-01;
stopDatePeriod1 = 2011-03-01;
startDatePeriod2 = 2011-04-01;
stopDatePeriod2 = 2012-03-01;
foreach(DateTime d in dates) {
if (d => startDatePeriod1 && d <= startDatePeriod1) {
adapterBonus.InsertPeriod1Query(// insert to database));
} else if(d => startDatePeriod2 && d <= stopDatePeriod2) {
adapterBonus.InsertPeriod2Query(// insert to database));
}
}
seems like you just need a simple query for each bonus period, something like ...
var period1Dates = date.Where(date => date >= startDate1 && date <= stopDate1);
var period2Dates = date.Where(date => date >= startDate2 && date <= stopDate2);
adapterBonus.InsertPeriod1(period1Dates);
adapterBonus.InsertPeriod2(period2Dates);
As Daniel says, you're checking if all the dates are within each period, which it sound like will never be true, so nothing will be happening.

Categories

Resources