LINQ Expression to get member value and can be translated to SQL? - c#

I have a complex query where certain DateTime members of a model entity are being used multiple times, but not always the same members. I'd like to know if I can put the "getting" of the member in an Expression, so I don't have to repeat that piece of code.
A simplified version of my current code looks like this:
var getTargetDate = ((Expression<Func<Order, DateTime>>)(o => o.OrderDate)).Compile();
if (delivery)
getTargetDate = ((Expression<Func<Order, DateTime>>)(o => o.DeliveryDate)).Compile();
return orders.Where(o => getTargetDate(o) >= fromDate && getTargetDate(o) < toDate);
This code compiles, but gives me the runtime Exception:
Exception thrown: 'System.NotSupportedException' in System.Data.Linq.dll
Additional information: Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.
Is there a way to put the "getting" of the DateTime in a variable or method that can be translated to SQL?

This does not literally answer the question, but it does provide a way around the code duplication posed in it.
Put the desired member and the entity itself in an anonymous object, perform the relevant part of the original query on the member, then select out the original entity:
orders = orders.Select(o => new { o,
TargetDate = delivery ? o.DeliveryDate : o.OrderDate
})
.Where(o => o.TargetDate >= fromDate && o.TargetDate < toDate)
.Select(o => o.o);

Related

Entity Framework refusing Date comparison The specified type member 'Date' is not supported in LINQ to Entities

I'm trying to retrieve all the records that match today's date, but I get this exception when I run
System.NotSupportedException: 'The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.'
I tried this solution
https://stackoverflow.com/a/14601775/13211556
but no effect same exception, also tried to change the column in the DB to Date only instead of DateTime.
here is the code:
List<int> Ids = context.Record
.Where(rec => DbFunctions.TruncateTime(rec.Date.Date) == date)
.Select(rec => rec.Id)
.ToList();
For better performance you have to use comparison operators. You have date without time, so add one day and write appropriate LINQ query.
var nextDay = date.AddDays(1);
List<int> Ids = context.Record
.Where(rec => rec.Date >= date && rec.Date < nextDay)
.Select(rec => rec.Id)
.ToList();
Only in this case indexes

LINQ to Entities does not recognize the method?

var tmp = productDBSet.Where(x => x.lastUpdate >= DateTime.MinValue && x.lastUpdate.Value.ToString("MM/yyyy") == curMonth).Select(x => x.ID);
While I run above code, I got this error message:
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated
into a store expression.
Also I tried,
var tmp = productDBSet.Where(x => x.lastUpdate >= DateTime.MinValue && x.lastUpdate.Value.ToString("MM/yyyy") == curMonth).ToList().Select(x => x.ID);
But same,
How can I solve that?
As the error message is telling you, the ToString method of DateTime isn't supported.
Since you're just trying to determine if the month and year of the date match a given value, you can just compare the actual month and year, rather than trying to get a string containing the month and year that you compare with.
x.lastUpdate.Value.Year == yearToCompareWith &&
x.lastUpdate.Value.Month = monthToCompareWith
You cannot use ToString() in Linq to Entities. Try something like this (I've assumed that x.lastUpdate is of type "DateTime"):
x.lastUpdate.Month == curMonth && x.lastUpdate.Year == curYear
This happens, because LINQ to Entities is translated to SQL queries, and therefore method ToString is not recognised.
You can not use extension methods in linq queries, since these are unable to get converted to equivalent Sql Queries. You can use following linq:
var tmp = productDBSet.Where(x => x.lastUpdate >= DateTime.MinValue && x.lastUpdate.Month == curMonth && x.lastUpdate.Year == curYear).Select(x => x.ID);

Linq with data Error condition ( 'Date' is not supported in LINQ)

I am using a LINQ statement to get some data from the table based on data value:
var oDay = diabeticDB.user_data
.Where(y => y.date >= DateTime.Now.Date
& y.BG != null
& y.userid == u)
.Average(x => x.BG).Value;
I get the following error:
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
The expression contained in Where(...) is converted to SQL, and the EF query provider (that does this conversion) does not understand DateTime.Now.Date.
The expression can contain a specific value, though - so create a local variable for today's date and use that:
var today = DateTime.Now.Date;
var oDay = diabeticDB.user_data
.Where(y => y.date >= today & y.BG != null & y.userid == u)
.Average(x => x.BG).Value;

Error using EF6 DbFunctions.TruncateTime comparing DateTime

I`m trying to retrieve some data from a data range using the following code:
var rotas = db.X.Where(r => r.DataDaExecucao != null)
.Where(r => System.Data.Entity.DbFunctions.TruncateTime(r.Date.Value) >= System.Data.Entity.DbFunctions.TruncateTime(startDateTime))
.Where(r => System.Data.Entity.DbFunctions.TruncateTime(r.Date.Value) < System.Data.Entity.DbFunctions.TruncateTime(endDateTime))
.Join(db.T, r => r.Id, t => t.X_Id.Value,
(r, t) => new
{
id = r.Id,
start = r.Date.Value.ToString("s"),
end = r.Date.Value.AddDays(1).ToString("s"),
title = t.Z.Name,
allday = false
}).ToList();
"Date" properties are Nullable< DateTime>.
I`m getting the following error message:
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
Exception Details: System.NotSupportedException: LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
Also, I don`t have the System.Data.Entity.dll assembly referenced in my csproj.
Ideas?
Thank you, in advance.
You can change the anonymous type using SqlFunctions where it will also generate the sql query.
In your case you use ToString("s"), meaning you want to get the date part of second that can be replaced by SqlFunctions::DatePart. And Date::AddDays can be replaced by SqlFunctions::DateAdd.
new
{
id = r.Id,
start = SqlFunctions.DatePart("s", r.Date),
end = SqlFunctions.DatePart("s", SqlFunctions.DateAdd("d", 1, r.Date)),
title = t.Z.Name,
allday = false
}
DateTime.ToString() cannot be converted into a SQL statement by LINQ to Entities. e.g.
start = r.Date.Value.ToString("s")
The thing to do is call .ToList() to force the LINQ to Entities to execute its underlying SQL query. That way the remainder of the LINQ statement will use LINQ to Objects (in-memory query of a collection of objects).
In your case I would break the LINQ statement into 2 parts:
The first half which queries the DB with LINQ to Entities SQL generation, and calls .ToList() at the end
The second half which runs LINQ to Objects to do the in-memory part.

Convert string to long type and use in a linq query within asp.net MVC

Is it possible within Linq in C#, to convert a string field in a database, to a long type - and use it in the query?
Here, tme is a unix time (long) - but the field in the database, targetdate - is a string.
I've tried:
var qbt = db.Calls
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
However I get the message: LINQ to Entities does not recognize the method 'Int64 Parse(System.String)' method, and this method cannot be translated into a store expression.
I know you can convert before the linq query, but is there any way of using it WITHIN the linq query?
Thanks for any help,
Mark
try
var qbt = db.Calls.ToList()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
if you have many records you can limit them by team first and then call ToList like below
var qbt = db.Calls.Where(x => x.team == id).ToList()
.Where(i=>long.Parse(i.targetdate) <= tme);
Or You can use AsEnumerable
var qbt = db.Calls.AsEnumerable()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
This is to do with the way the Linq is translated into the backing query language, it might be easier to do a string comparison in this case, using tme.ToString(). If you pull the full collection down first, you could query like this but that means what it says: pulling down the full unfiltered (or at least less filtered) set.
You have to either change the database table to not store a string (you could create a computed column that converts it to a long or create a view if you cannot modify the existing table) or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.
var stringTme = tme.ToString(CultureInfo.InvariantCulture);
var qbt = db.Calls
.Where(x => x.team == id && ((x.targetdate.Length < stringTme.Length)
|| (x.targetdate.Length == stringTme.Length && x.targetdate <= stringTme)));
You have to either change the database table to not store a string or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.please use long.Parse()

Categories

Resources