Entity Framework ToString method - c#

Following code block throws error.
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
db.tbOnIgmHawbDetails
.Where(s => !db.tbImpoExaminations.Any(x => x.Hawb.ToString() == s.Hawb) && s.AwbNo == p)
.Select(s => s.Hawb).ToList();
Any suggestion? why this happen and what is the solution?

.ToString() is supported properly going forward with EF 6.1: http://blogs.msdn.com/b/adonet/archive/2014/03/17/ef6-1-0-rtm-available.aspx

You could try with SqlFunctions.StringConvert... Use the decimal conversion:
SqlFunctions.StringConvert((decimal)p.x.Hawb).TrimLeft() == ...
(the TrimLeft is necessary because the STR function of SQL will right align the number)

If s.Hawb is already string type (the error message suggests so), then remove the part .ToString() from your query.
The reason for it is that in LINQ2SQL, you can only use those language constructs that can be translated into SQL. For example, if you try to use RegEx in your C# expression, then SQL does not have a corresponding construct for RegEx, and thus LINQ cannot translate and execute your query.

Easily add .AsEnumerable() before the .ToString() and those methods that L2E doesn't support:
var asen = db.tbOnIgmHawbDetails.AsEnumerable();
var result = asen.Where(s => !asen.Any(x => x.Hawb.ToString() == s.Hawb) && s.AwbNo == p)
.Select(s => s.Hawb).ToList();
That should works. However if not, try to perform your query by linq-to-objects syntax:
var result = from a in asen
where ...
select ...;

do not use ToString
just use like
x.Hawb + "" == s.Hawb

Related

How can I query a database with LINQ when the column is a number but I have a string in the WHERE?

I am using this code:
query = String.IsNullOrEmpty(options.PhraseNum) ?
query :
query.Where(w => w.PhraseNum == Convert.ToInt32(options.PhraseNum));
However I get an error:
LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.
Is there a way I can do this in LINQ and if not how can I convert outside of this and have the conversion not cause an exception if the string is not null?
Only modify query if the string can be parsed to an int, which is an implicit check if it isn't null or empty:
if (int.TryParse(options.PhraseNum, out var phraseNum))
{
query = query.Where(w => w.PhraseNum == phraseNum);
}
Before C# 7 the syntax was
int phraseNum;
if (int.TryParse(options.PhraseNum, out phraseNum))
etc.
It looks like LINQ is trying to evaluate the expression Convert.ToInt32(options.PhraseNum) on the server side as part of the WHERE clause.
Redo the code so that the variable is cast explicitly on the client-side outside the query expression:
Int32 phrase_num = String.IsNullOrEmpty(options.PhraseNum) ? 0 : Convert.ToInt32;
query = String.IsNullOrEmpty(options.PhraseNum) ? query : query.Where(w => w.PhraseNum == phrase_num);
Or for a tidier approach overall:
if(!String.IsNullOrEmpty(options.PhraseNum))
{
Int32 phrase_num = Convert.ToInt32(options.PhraseNum);
query = query.Where(w => w.PhraseNum == phrase_num);
}
I think that should resolve the problem and preserve the intended program logic.
EDIT: I'd endorse Gert Arnold's approach above if you are using the latest C# version, where out parameters can be declared inline in the TryParse method call itself.

How to add combined columns in linq where clause?

My query is like this:
var list = context.Items
.Where(i => i.Title.StartsWith(searchValue) ||
(i.Title + string.format("{0}prep", i.OrderNumber))
.StartsWith(searchValue))
.ToList();
But I am gettings exception - object not set to the instance of the object.
I also tried to add .AsEnumerable after .Where but doesn't work.
Without AsEnumerable I am getting:
LINQ to Entities does not recognize the method 'System.String
Format(System.String, System.Object)' method, and this method cannot
be translated into a store expression.
What I did wrong here?
What I did wrong here?
The answer is in the exception message:
LINQ to Entities does not recognize the method System.String Format(System.String, System.Object) method, and this method cannot be translated into a store expression.
In other words, string.Format method is not supported because it cannot be translated to SQL query.
Fortunately string concatenation is supported, so you can use this instead:
var list = context.Items.Where(i => i.Title.StartsWith(searchValue)
|| (i.Title + i.OrderNumber + "prep").StartsWith(searchValue))
.ToList();

ASP.NET Entity Framework .Where() with Lesser than

How can I make this lesser than or equal work in my .Where() clause? I am getting an error.
var filteredProducts = Products.Where(p => p.State.Contains("Bruikbaar"))
.Where(p => p.Privilege <= ui.GetPrivilegeNumber())
.ToList();
Error:
LINQ to Entities does not recognize the method 'Int32 GetPrivilegeNumber()' method, and this method cannot be translated into a store expression.
I hope this question is never asked before. Googled couldn't find it either or I am using the wrong words to express my problem.
ui.GetPrivilegeNumber() is not a recognized method.
Use this:
var uiPrivilege = ui.GetPrivilegeNumber();
var filteredProducts = Products.Where(p => p.State.Contains("Bruikbaar"))
.Where(p => p.Privilege <= uiPrivilege)
.ToList();
And as other users mentionted, you can optimize your Where.
EF does not execute method calls which you use in predicates. It stores them as expression (i.e. syntax tree) and then analyzes this tree to build SQL query by translating C# code to SQL code. It cannot translate GetPrivilegeNumber() method call into SQL, because there is no appropriate SQL code for that. So all you need is move this method call out of expression and pass only result of method call instead:
var privilegeNumber = ui.GetPrivilegeNumber();
var filteredProducts = Products.Where(p => p.State.Contains("Bruikbaar"))
.Where(p => p.Privilege <= privilegeNumber)
.ToList();
Now privilegeNumber is just an integer variable which is translated into SQL parameter
SELECT * FROM Products p
WHERE p.State LIKE '%Bruikbaar%' AND p.Privilege <= #privilegeNumber
You need to move ui.GetPrivilegeNumber() outside of the query. You can also merge those Where queries into a single one:
var privilegeNumber = ui.GetPrivilegeNumber();
var filteredProducts = Products.Where(p =>
p.State.Contains("Bruikbaar")
&& p => p.Privilege <= privilegeNumber)
.ToList();
You can use other evaluation method inside LinQ. To simplified the code, you can use it in little old way of writing LinQ.
var uiPrivilege = ui.GetPrivilegeNumber();
var filteredProducts =(from p in Products
where p.State.Contains("Bruikbaar") && p.Privilege <= uiPrivilege
select p).ToList();
The above query generate same output but easy to understood.

LINQ to Entities does not recognize the method IsNullOrWhiteSpace

I have the below code:
var countries = from c in db.Countries
where (string.IsNullOrWhiteSpace(searchAlpha2) || (c.Alpha2 ?? string.Empty).ToUpper().Contains(searchAlpha2.ToUpper()))
&& (string.IsNullOrWhiteSpace(searchAlpha2) || (c.Alpha3 ?? string.Empty).ToUpper().Contains(searchAlpha3.ToUpper()))
&& (string.IsNullOrWhiteSpace(searchName) || (c.Name ?? string.Empty).ToUpper().Contains(searchName.ToUpper()))
select c;
This code uses Entity Framework v6 Code First over a SQL database.
Aside from performance, if I don't include the IsNullOrWhitespace I get no results when the filter criteria are blank (I've tested both null and blank values); however when a value is present this works as expected.
I'm getting the error:
LINQ to Entities does not recognize the method 'Boolean IsNullOrWhiteSpace(System.String)' method, and this method cannot be translated into a store expression.
I'm trying to use the searchXXX strings to filter on columns. I've tried using RegEx.IsMatch, SqlMethods.Like, and the code below, but all give me errors saying those functions are not allowed (errors come from either EntityFramework.SqlServer or from Linq to Entities). I've seen numerous posts on here where this has been done successfully though - so wonder if I'm missing something fundamental?
If you want to use your statement in current form you might want to replace
string.IsNullOrWhiteSpace(searchAlpha2)
to
!(searchAlpha2 == null || searchAlpha2.Trim() == string.Empty)
and all the other values too, for it to get translated to working SQL.
Update: Copied from comment by #DavidKempfner
As of EntityFramework.6.2.0 it generated SQL that checked for
!(searchAlpha2.Trim() == string.Empty),
I.E. It ignored the searchAlpha2 == null || part.
Use this instead:
!string.IsNullOrEmpty(entity.searchAlpha2.Trim())
I would suggest a different approach - use the ability to build queries up on the fly, and thus avoid passing optional query parameters to the expressions altogether - this will result in improved query plans when parsed to sql and executed on the database.
Also, if your database (?SqlServer) is not set to case sensitive collation (i.e. xx_CI_xx), you can avoid the casing conversion as well, as it is redundant:
var myQueryable = db.Countries.AsQueryable();
if (!string.IsNullOrWhiteSpace(searchAlpha2))
{
myQueryable = myQueryable.Where(c => c.Alpha2.Contains(searchAlpha2));
}
...
var countries = myQueryable.ToList();
You can get this and a bunch more functionality using PredicateBuilder
Update
JB: based on StuartLC's answer, here's the code amended to use PredicateBuilder:
var predicate = PredicateBuilder.True<Country>();
if (!string.IsNullOrWhiteSpace(searchAlpha2))
predicate = predicate.And(c => c.Alpha2 != null ? c.Alpha2.Contains(searchAlpha2) : false);
if (!string.IsNullOrWhiteSpace(searchAlpha3))
predicate = predicate.And(c => c.Alpha3 != null ? c.Alpha3.Contains(searchAlpha3) : false);
if (!string.IsNullOrWhiteSpace(searchName))
predicate = predicate.And(c => c.Name != null ? c.Name.Contains(searchName) : false);
IQueryable<Country> countries = db.Countries.AsExpandable().Where(predicate);
when you use linq in Entity Framework to get data from DataBase you need to use only with functions that the Entity Framework can convert to sql query.
I know that there an already accepted answer for this question but I got an idea to share.
Instead of putting multiple checks in the LINQ or using if statement to apply where clause on list result, you can use a simple trick. Just declare a bool variable and assign IsNullOrWhitespace of add to linq like:
bool isNull = string.IsNullOrWhiteSpace(searchAlpha2);
var countries = db.Countries.Where(c => isNull || c.Alpha2.Contains(searchAlpha2)).ToList();

Why is Trim() failing in this expression?

I have the following method:
var catIds = DetachedCriteria.For<Category>()
.Add<Category>(c => c.TypeCode == "IMA")
.SetProjection(LambdaProjection.Property<Category>(s => s.Id));
This is returning nothing because in the database the field is nchar(10). I want to Trim() the TypeCode value, as follows:
var catIds = DetachedCriteria.For<Category>()
.Add<Category>(c => c.TypeCode.Trim() == "IMA")
.SetProjection(LambdaProjection.Property<Category>(s => s.Id));
but it returns the NHibernate error:
Unrecognised method call in epression c.TypeCode.Trim()
One of the guys here in the office thinks it's because HHibernate doesn't know how to convert .Trim() to SQL (or something along those lines). Can anyone suggest how I can fix this?
Try right-padding the value you're comparing with to the required length, for example:
string cmpValue = "IMA".PadRight(10);
var catIds = DetachedCriteria.For<Category>()
.Add<Category>(c => c.TypeCode == cmpValue)
.SetProjection(LambdaProjection.Property<Category>(s => s.Id));
Your office guys are correct -- the linq provider doesn't know how to translate C# string.Trim() to whatever sql variant it is.
As for the fix, linq can make you do the damndest things -- like padding your data to match CHAR(10) rather than TRIM() to a 'normal' string.
I hope the following code may solve your problem:
Func<string, string> trimmer = (x) => {
return !string.IsNullOrEmpty(x) ? x.Trim() : string.Empty; };
and then use it like:
var catIds = DetachedCriteria.For<Category>()
.Add<Category>(c => trimmer(c.TypeCode) == "IMA")
.SetProjection(LambdaProjection.Property<Category>(s => s.Id));

Categories