Whats wrong in this Linq query - c#

var MyCours = Db.COURS.Where(C => C.CLASSE_ID == ClassID
&& DateTime.Now>= C.START_DATE
&& DateTime.Now <= C.END_DATE)
.ToList();
Some change still dont work !

A likely problem is that the provider can't project DateTime.Compare into a SQL statement. There is potentially also a logical error in the direction of comparison (unless you really want enddate < now < startdate), and I would also suggest using .ToList() to materialize into a list:
var theTimeNow = DateTime.Now;
var MyCours = Db.COURS.Where(C => C.CLASSE_ID == ClassID
&& theTimeNow >= C.START_DATE
&& theTimeNow <= C.END_DATE)
.ToList();
Projecting DateTime.Now into a variable isolates the non-determinism of it, i.e. to ensure that both comparisons are against the same time.

Related

EF Core declaring multiple variables on complex Where Clause

I have this LINQ Where clause that is declaring 2 variables on the SQL query
var parkingLotPrice =
_context.ParkingLotPrice
.Where(x => currentDate >= x.EffectiveDate && (currentDate <= x.ExpiryDate || x.ExpiryDate == null))
.ToQueryString();
It generates this SQL Query:
DECLARE #__currentDate_0 datetime2 = '2021-07-21T17:48:29.1106534-06:00';
DECLARE #__currentDate_1 datetime2 = '2021-07-21T17:48:29.1106534-06:00';
SELECT [p].[ParkingLotId],
[p].[PriceScheduleId],
[p].[EffectiveDate],
[p].[ExpiryDate]
FROM [ParkingLotPrice] AS [p]
WHERE (#__currentDate_0 >= [p].[EffectiveDate]) AND ((#__currentDate_1 <= [p].[ExpiryDate]) OR [p].[ExpiryDate] IS NULL)
Note: the declarations contains the same value.
The problem is the (currentDate <= x.ExpiryDate || x.ExpiryDate == null).
If I remove the null evaluation, it only declares 1 variable.
DECLARE #__currentDate_0 datetime2 = '2021-07-21T17:32:31.3980763-06:00';
SELECT [p].[ParkingLotId],
[p].[PriceScheduleId],
[p].[EffectiveDate],
[p].[ExpiryDate]
FROM [ParkingLotPrice] AS [p]
WHERE (#__currentDate_0 >= [p].[EffectiveDate]) AND (#__currentDate_0 <= [p].[ExpiryDate])
Is there a way of keeping the Where evaluation, but only declare 1 variable?
And what is wrong with it? Does it return a wrong result? I created hundreds queries with null and without and they always returned the right result.
I can see the real problem in your query. The way you compare dates. It will compare times too. In some cases it will return a wrong result. I highly recommend you to compare only dates
var parkingLotPrice = _context.ParkingLotPrice
.Where(x => EF.Functions.DateDiffDay(x.EffectiveDate,currentDate) >=0
&& (x.ExpiryDate == null || EF.Functions.DateDiffDay(currentDate,x.ExpiryDate)>=0 )).ToList();
or if you need some time try this
var parkingLotPrice = _context.ParkingLotPrice
.Where(x => EF.Functions.DateDiffMinute(x.EffectiveDate,currentDate) >=0
&& (x.ExpiryDate == null || EF.Functions.DateDiffMinute(currentDate,x.ExpiryDate)>=0 )).ToList();

Can't compare dates using SQLite with EF6

I'm trying to compare dates using Linq to Entities on a SQLite database. The following code works, but I need to trim off the time portion to get the correct results.
return (from c in Context.Car
join d in Context.Driver on c.CarID equals d.DriverID
join r in Context.Rides on c.CarID equals r.RideID into rideJoin
from rides in rideJoin.DefaultIfEmpty()
where c.IsActive && d.IsActive
group rides by new { c.CarID, d.FullName, d.HireDate, d.FirstPayRiseDate } into grp
select new MyCustomClass
{
CarID = grp.Key.CarID,
Driver = grp.Key.FullName,
NumberOfRides = grp.Count(x => x != null && x.RideDate >= grp.Key.HireDate && x.RideDate <= grp.Key.FirstPayRiseDate)
}).OrderBy(x => x.Driver ).ToList();
I've tried using System.Data.Entity.DBFunctions like so and I get this error:
NumberOfRides = grp.Count(x => x != null && DbFunctions.TruncateTime(x.RideDate) >= grp.Key.HireDate && DbFunctions.TruncateTime(x.RideDate) <= grp.Key.FirstPayRiseDate)
SQL logic error or missing database no such function: TruncateTime
I also get the same error with DBFunctions.DiffDays()
I've also tried casting to Date like so and get this error:
NumberOfRides = grp.Count(x => x != null && x.RideDate.Date >= grp.Key.HireDate && x.RideDate.Date <= grp.Key.FirstPayRiseDate)
'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported
What gives? How am I supposed to do Date functions in Linq to Entities with SQLite??
I need to trim off the time portion to get the correct results
No you don't. If you want to include the rows from startDate through endDate inclusive then just use
... && x.RideDate >= startDate && x.RideDate < endDate.AddDays(1)
(Note that the second comparison is now "strictly less than".)
How are you storing dates on the database ? as unix time integrs ?
in that acse you can amend your connection string to include this following config setting and it will make it easy to read the datetime value via EF.
datetimeformat=UnixEpoch;datetimekind=Utc
So something like :
data source="|DataDirectory|\data.sqlite";datetimeformat=UnixEpoch;datetimekind=Utc
Ref: https://stackoverflow.com/a/24323591/3660930

Short Date in Linq

I want my query to stop displaying time and just the date. This is what I've tried to far:
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = new DateTime(z.ActivityDate.Year, z.ActivityDate.Month, z.ActivityDate.Day),
Subject = z.Subject
}).ToList();
And
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = z.ActivityDate.Date,
Subject = z.Subject
}).ToList();
And both didn't work.
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression. when trying to apply a string method.
You can use anyDate.ToString("ddMMyyyy");//any preferred format.
Not sure if that is what you are looking for!
Your queries return objects with Date & Subject properties.
In the Date property you are passing a DateTime object. In order to display the short date you have a "ToShortDateString()" function on a date.
If you dont want to work with a date and prefer selecting a string, then do the conversion inside the linq query.
Use this if you want to return strings:
var q = (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo && z.ActivityDate >= EndDateTo && z.Indepth == false
select new { Date = z.ActivityDate.Date.ToShortDateString(), Subject = z.Subject }).ToList();
You would need to perform the formatting at the time of the binding. As you don't show the actual binding code, it is hard to specifically address your situation but lets look at what happens in your query:
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo && z.ActivityDate >= EndDateTo && z.Indepth == false
select new { Date = z.ActivityDate.Date, Subject = z.Subject }).ToList();
Once LINQ handles this query, the resulting Query variable should be of type List<DateTime>. The way you have the query working you would return a list of DateTimes in a format like this:
2014-04-23 00:00:00
2014-03-28 00:00:00
etc...
In order to bind this without the time value, you need to call ToString() on each element (or the desired element) of the list at the time of binding.
Assuming you are using a ListBox or something similar you could write the following:
foreach (var date in myList) //this is the resultant list from the query
{
listBox1.Items.Add(date.ToString("MM/dd/yyyy");
}
If you are literally binding to a DataSource property, you will need to convert your List<DateTime> to a List<string> with the formatted values.
ToShortDateString() may help you.
Query= (from z in ctx.Interactions
where z.ActivityDate <= StartDateTo
&& z.ActivityDate >= EndDateTo
&& z.Indepth == false
select new
{
Date = z.ActivityDate.ToShortDateString(),
Subject = z.Subject
}).ToList();
convert date into string like below
string stringDate=string.empty;
stringDate=Convert.ToDateTime("2014-04-23 00:00:00").ToShortDateString();
it will give output like
2014-04-23

LINQ Group By with subquery

I am trying to make a query on LINQ using a GroupBy, where on the Select statement I try to make some kind of subquery. The idea is that I have 7 days to look for, I need to get the average value of these last 7 days but also the current value for the current day. So I have tried the following code:
var oDate = DateTime.UtcNow;
var startDate = oDate.AddWorkingDays(-7);
var endDate = oDate.AddWorkingDays(-1);
var races = RaceTimes.Where(
x =>
x.ODate >= startDate && x.ODate <= oDate && x.Status == "Finished")
.GroupBy(x => x.Athletes.Name).Select(x => new
{
Name = x.Key,
Description = "Just a Random Description for now",
ODate = oDate,
SevenDaysAvg = (int?)x.Where(y => y.ODate >= startDate && y.ODate <= endDate).Average(y => SqlFunctions.DateDiff("s", y.StartTime, y.EndTime)),
RaceTime = (int?)x.Where(y => y.ODate == oDate).Average(y => SqlFunctions.DateDiff("s", y.StartTime, y.EndTime))
}).ToList().Where(x => x.RaceTime!= null).ToList();
The SevenDaysAvg (average) works fine, it returns me the average of the last 7 days races. However, Latency is always returning me null.
I am trying to make the translation of my query from SQL, which works fine:
...
AVG(case when h.ODate BETWEEN '20140219' AND '20140227' then DATEDIFF(SECOND, h.StartTime, h.EndTime) else null end) AS SevenDaysAvg,
AVG(case when h.ODate = '20140227' then DATEDIFF(SECOND, h.StartTime, h.EndTime) else null end) AS RaceTime,
...
So what am I doing wrong in my LINQ query? This what I am doing is not possible? I've also tried another aproach. First calculate all averages, and then in the main query have something like:
SevenDaysAvg = averages.Where(y => y.Name== x.Athletes.Name).Select(y => y.SevenDaysAvg).FirstOrDefault()
Once again, this approach didnt work, it keeps giving me empty results. Whats wrong here?

c# lambda expression using Sum for multiple comparisons

I'm trying use the Sum method in a lambda expression for a comparison, but I want to use it for multiple comparisons. How do I accomplish this? I've looked at "Let" and "SelectMany", but I haven't been able to find an answer.
Below is what the code looks like:
return _dbContext.All<Table>()
.Where(table => table.CurrentLevel <= salesCriteria.MaxTableLevel)
.Where(table => table.Leg
.Where(leg=> salesCriteria.StartDate <= leg.AddDate)
.Where(leg=> leg.AddDate <= salesCriteria.EndDate)
.Sum(leg => leg.Width) <= salesCriteria.MaxGoalAmount);
As you can see, I'm trying to get all Tables with certain criteria that have Legs with certain criteria and whose width all add up to be less than a certain value. I would also like to make sure that the Sum is greater than a certain min value. However, I can't do that here since as soon as I do .Sum, I lose the list. So how would I accomplish that here? All I want is minValue <= .Sum() <= maxValue
It sounds like you want something like:
return _dbContext.All<Table>()
.Where(table => table.CurrentLevel <= salesCriteria.MaxTableLevel)
.Select(table => new {
table,
legWidth = table.Leg
.Where(leg=> salesCriteria.StartDate <= leg.AddDate)
.Where(leg=> leg.AddDate <= salesCriteria.EndDate)
.Sum(leg => leg.Width)
})
.Where(x => x.legWidth <= salesCriteria.MaxGoalAmount &&
x.legWidth >= salesCriteria.MinGoalAmount)
.Select(x => x.table);
So the Select here is the equivalent of using a let in a query expression.
As a query expression, this would be:
return from table in _dbContext.All<Table>()
where table.CurrentLevel <= salesCriteria.MaxTableLevel
let legWidth = table.Leg
.Where(leg=> salesCriteria.StartDate <= leg.AddDate)
.Where(leg=> leg.AddDate <= salesCriteria.EndDate)
.Sum(leg => leg.Width)
where legWidth <= salesCriteria.MaxGoalAmount &&
legWidth >= salesCriteria.MinGoalAmount
select table;
To get the power of let, you need to switch from method-chaining syntax to query expression syntax. Try this:
var goodTables =
from table in _dbContext.All<Table>()
where table.CurrentLevel <= salesCriteria.MaxTableLevel
let sumOfWidthOfGoodLegs =
table.Leg
.Where(leg=> salesCriteria.StartDate <= leg.AddDate)
.Where(leg=> leg.AddDate <= salesCriteria.EndDate)
.Sum(leg => leg.Width)
where sumOfWidthOfGoodLegs <= salesCriteria.MaxGoalAmount
// can insert another where on sumOfWidthOfGoodLegs here as required
select table;
return goodTables.ToList();
I note that this is checking the width-sum of only the good legs - I'm not convinced this is what you want, but it's what you're doing at present.

Categories