Linq to entities - Lambda - Concatenate strings - c#

I would like to concatenate a string using lambda to compare that concatenated value against a certain condition.
Invoices = Invoices.Where(f => ((string)f.invoice_prefix + String.Format("{0:0000}", Convert.ToInt32(f.invoice_number))).ToLower().Equals(condition7));
But I get an error message :
The name 'f' does not exist in the current context
Tried several String.Format and String.Concat variants like
Invoices = Invoices.Where(f => (String.Format("{0}{1}",f.invoice_prefix,String.Format("{0:0000}", Convert.ToInt32(f.invoice_number)))).ToLower().Equals(condition7));
but no success... Can somebody help me with the syntax?
Thanks in advance!

Linq to Entities doesn't understand all of the .NET framework methods.
In order to run this as a SQL statement on the database, you need to only use operators that can be converted to SQL. That means you need to re-write your predicate using primitive data types.
So something like this:
string prefixCondition = ...
int invoiceNumberCondition = ...
Invoices.Where( f =>
f.invoice_prefix == prefixCondition
&&
f.invoice_number == invoiceNumberCondition
)
I recommend using LinqPad to test with, as it shows you the generated SQL statement.

Related

How can I issue a LINQ query to a SQL Server to check if a column value starts with a word?

I have this already
if (options.English != null) query = query
.Where(w => w.English.Contains(options.English));
What I would like to do is to extend this (maybe with another if clause) to make it so that if:
a user enters ^abc then my query would check if the word starts with "abc".
a user abc then it would check if the column contains "abc"
I am using a SQL Server back-end database. Could anyone give me a suggestion as to how I could implement this functionality.
Assuming that you're using Entity Framework, you can use the StartsWith() and EndsWith() methods, to achieve the same results as Contains() except only at the beginning or the end of a string. It will generate the code for you.
Then simply create conditional statements in your code, in order to determine which one of the methods you should use.
Some word of advice:
There might be a bug with EF Core, in which it turns StartsWith("string") into LIKE "string%" which might yield incorrect results with strings, containing wildcard characters such as "_".
So I'd advise you to use plain SQL with EF Core, and given that you're using SQL Server as a DBMS, query like that:
if (searchText.StartsWith("^"))
{
var result = query.FromSql($"SELECT something FROM table WHERE PATINDEX({searchText.Substring(1)}, something) = 1");
}
else
{
var result = query.FromSql($"SELECT * FROM table WHERE PATINDEX({searchText.Substring(1)}, something ) <> 0");
}
With PATINDEX() you will get correct results even if your pattern string contains wildcard characters - escaping potential bugs with relying on StartsWith() and EndsWith() to generate proper SQL code.
But that's only for EF Core, EF 6 works like a charm the way other people answered :)
You can put that choice in a conditional statement:
IQueryable<Whatever> query = ...;
if (searchText.StartsWith("^"))
{
query = query.Where(w => w.English.StartsWith(searchText.Substring(1)));
}
else
{
query = query.Where(w => w.English.Contains(searchText));
}
You can also do the same comparison inline, but that'll generate very ugly SQL, if it even works:
query = query.Where(w =>
searchText.StartsWith("^")
? w.English.StartsWith(searchText.Substring(1))
: w.English.Contains(searchText));
Do note that you generally don't want to search text using SQL, as that results in a pretty poor user experience. Take a look at full-text indexing.
if (options.English != null)
{
bool englishStartsWith = options.English.StartsWith("^");
if(englishStartsWith)
{
query = query.Where(w => w.English.StartsWith(options.English.Substring(1)));
}
else
{
query = query.Where(w => w.English.Contains(options.English));
}
}

Unrecognized expression node ArrayIndex using linq with predicate

Hi i have this query...
List<VisitorsVo> lstVisitors = new List<VisitorsVo>();
var predicate = ReturnPredicateForVisitors(p_htVisitor);
if (predicate != null)
{
lstVisitors = (from n in context.TBL_VISITORs.Where(predicate)
select new VisitorsVo
{
VisitId = n.VISIT_ID,
VisitorName = n.VISITOR_NAME,
ResidentDuration = n.ENQUIRY_PATIENT_DURATION.Split(';')[0] + " " + n.ENQUIRY_PATIENT_DURATION.Split(';')[1],
}).ToList();
}
but i am getting Unrecognized expression node ArrayIndex error how can i overcome...
here i am checking condition in where using predicates....
It looks like this is LINQ to Entities, not plain LINQ. Is your context an Entity Framework or LINQ to SQL context?
If so, then LINQ to Entities/SQL will try to translate this expression into SQL, which it cannot do if it contains function calls it doesn't know or that have no SQL equivalent.
My money is on the use of Split(); I'll bet that LINQ to Entities barfs on that.
What you can do is modify your query to get rid of the Split(), and afterward you can query lstVisitors (which is now just an in-memory data structure, it has no link to Entity Framework) and use Split() there.
If you need to split a column that means you can hold that data in two separate columns.
If I were you I'd go to the database design and convert ENQUIRY_PATIENT_DURATION into 2 columns and do it properly. Your code seems very error prone.

MVC LINQ with Where condition

I am trying to make search function in my project.
Currently, I want to convert decimal value to string for comparing with searchString.
When I put like this:
public ActionResult Search(string searchString)
{
var product = from a in _db.Product.Include(a => a.Category)
select a;
if (!String.IsNullOrEmpty(searchString))
{
product = product.Where(a => a.model.ToUpper().Contains(searchString.ToUpper())
|| Convert.ToInt32(a.displaySize).ToString().Contains(searchString));
}
return View(product.ToList());
}
It has error,
'LINQ to Entities does not recognize the method 'System.String
ToString()' method'.
How can I compare decimal value with string value?
Could you help me?
Thanks.
You can't use C# functions that can't be converted to SQL like .ToString(). You can use LINQ to Objects instead if your table isn't very large by calling .ToList() before Where
product = product.ToList().Where(a => a.model.ToUpper().Contains(searchString.ToUpper())
|| Convert.ToInt32(a.displaySize).ToString().Contains(searchString));
EDIT:
You can use functions from SqlFunctions namespace. that functions can easily be converted to SQL.
You could try converting your string value (query parameter) to a decimal and comparing the reverse.
It looks like you are searching for two different things. I would split this linq statment at the ||. If you are looking for whatever a.model is, go to one method, if you are looking for the int value go to another and convert the search string to an int BEFORE the linq statment. That method would like something like:
int searchInt;
if(int.TryParse(searchString, out searchInt))
{
product = product.Where(a => a.displaySize == searchInt);
}
You have to do this because SQL doesn't have a ToString() method... so LINQ doesn't really know what to do with it. Remember that this all gets converted to SQL.

LINQ To SQL exception: Local sequence cannot be used in LINQ to SQL implementation

everybody.
I know, that this topic has been discussed yet. But, unfortunately, I didn't find any solution in existing answers.So, I have the next code:
public List<List<string>> DataTableParser(IQueryable<T> queriable)
{
//I missed the unnecessary code
return queriable.Select(SelectProperties).ToList();
//I missed the unnecessary code
}
private Expression<Func<T, List<string>>> SelectProperties
{
get
{
var properties = typeof(T).GetProperties();
//
return value => properties.Select
(
// empty string is the default property value
prop => (prop.GetValue(value, null) ?? string.Empty).ToString()
)
.ToList();
}
}
So, in the method DataTableParser I have the exception with the next message:
"Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator".
I don't use in my query "where" part. So I can't imagine how to use "Contains" operator. And I can't understand the reason of the exception.
Does anyone have any ideas? I will appreciate any help. Thanks.
try using
return queriable.AsEnumerable().Select(SelectProperties).ToList();
this evaluates the sql of the queriable first and creates in memory objects that will then be processable by reflection
linq to sql only knows how to translate an expression into sql. there is a limited number of expressions that are translatable to sql. the properties that represent your columns are translatable to sql.
queriable.Select(x=>x.MyColumn);
//is translatable to sql when there is a column that is named MyColumn in your table
queriable.Where(x=>x.MyColumn.Contains("X"))
//is translatable to sql as "...where MyColumn like '%X%' ..."
queriable.Select(x=> new { x.MyColumn, x.AnotherColumn})
//is translatable to sql for selecting multiple columns
queriable.Select(SelectProperties)
//is not translatable to sql because it does not return an expression that selects a single value, and its not an expression that returns a new object.
How do you intend to use this method?

How to use SQL 'LIKE' with LINQ to Entities? [duplicate]

This question already has answers here:
How to make LINQ execute a (SQL) LIKE range search
(3 answers)
Closed 2 years ago.
I have a textbox that allows a user to specify a search string, including wild cards, for example:
Joh*
*Johnson
*mit*
*ack*on
Before using LINQ to Entities, I had a stored procedure which took that string as parameter and did:
SELECT * FROM Table WHERE Name LIKE #searchTerm
And then I would just do a String.Replace('*', '%') before passing it in.
Now with LINQ to Entities I am trying to accomplish the same thing. I know there is StartsWith, EndsWith and Contains support, but it won't support it in the way that I need.
I read about "SqlMethods.Like" and tried this:
var people = from t in entities.People
where SqlMethods.Like(t.Name, searchTerm)
select new { t.Name };
However I am getting the following exception:
LINQ to Entities does not recognize the method 'Boolean Like(System.String,
System.String)' method, and this method cannot be translated into a store
expression.
How would I get this same functionality using LINQ to Entities?
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/6529a35b-6629-44fb-8ea4-3a44d232d6b9/
var people = entities.People.Where("it.Name LIKE #searchTerm", new ObjectParameter("searchTerm", searchTerm));
How to get it to work seamlessly:
in your EDMX model, add:
<Function Name="String_Like" ReturnType="Edm.Boolean">
<Parameter Name="searchingIn" Type="Edm.String" />
<Parameter Name="lookingFor" Type="Edm.String" />
<DefiningExpression>
searchingIn LIKE lookingFor
</DefiningExpression>
</Function>
just after the sections that start:
<edmx:ConceptualModels>
<Schema Namespace="Your.Namespace"...
Then, anywhere in your code, add this extension method:
//prior to EF 6 [System.Data.Objects.DataClasses.EdmFunction("Your.Namespace", "String_Like")]
//With EF 6
[System.Data.Entity.DbFunction("Your.Namespace", "String_Like")]
public static bool Like(this string input, string pattern)
{
/* Turn "off" all regular expression related syntax in
* the pattern string. */
pattern = Regex.Escape(pattern);
/* Replace the SQL LIKE wildcard metacharacters with the
* equivalent regular expression metacharacters. */
pattern = pattern.Replace("%", ".*?").Replace("_", ".");
/* The previous call to Regex.Escape actually turned off
* too many metacharacters, i.e. those which are recognized by
* both the regular expression engine and the SQL LIKE
* statement ([...] and [^...]). Those metacharacters have
* to be manually unescaped here. */
pattern = pattern.Replace(#"\[", "[").Replace(#"\]", "]").Replace(#"\^", "^");
return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
}
And there you have it.
Now you can do:
(from e in Entities
where e.Name like '%dfghj%'
select e)
or
string [] test = {"Sydney", "Melbourne", "adelaide", "ryde"};
test.Where(t=> t.Like("%yd%e%")).Dump();
Well, your choices are:
Use Contains. I know you don't like it, but it could probably be made to work.
Pick a function from SqlFunctions. They're all supported in L2E.
Map your own function.
+1 to #Yury for ESQL.
You can do this:
using System.Data.Entity; // EntityFramework.dll v4.3
var queryResult=db.Accounts.AsQueryable().Where(x => x.Name.Contains(queryKey));
because Linq to Entity can't transform the method Contains() to the SQL, but Linq to SQL can do this. I tried to find a method that can doing a cast, at last, AsQueryable(), also a generic version AsQueryable<T>(). I found I can do this using it this way in my case, but any side effect it has I don't know, maybe it will lose some feature at Entity.
the solution is to use SQLFunctions.PatIndex
var result = from c in items
where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
select c;
where 'searchstring' is the pattern to search
'fieldtoSearch' is the field to search
Patindex() supports search using string pattern search. The search is case insensitive.
Now, EF supports "LIKE" usage and you can use all sql wildcards. Check this out.
var people = from t in entities.People
select new { t.Name };
people = people.Where(x => DbFunctions.Like(x.Name, searchTerm));
You can do all these statements with LINQ like this
string _search = "johnson";
// joh* OR joh%
items.Where(i => i.Name.StartsWith(_search, StringComparison.OrdinalIgnoreCase));
// *son OR %son
items.Where(i => i.Name.EndsWith(_search, StringComparison.OrdinalIgnoreCase));
// *hns* OR %hns%
items.Where(i => i.Name.ToLower().Contains(_search));
var people = from t in entities.People
where t.Name.ToLower().Contains(searchTerm.ToLower())
select new { t.Name };
EDIT- I might be mixing syntax. I usually use extension methods; but contains will work.
It is easily achieved by following methods
var people = from t in entities.People
where t.Name.Contains(searchTerm)
select new { t.Name };
Use the following specifications to achieve wildcards
LIKE 'a%' => StartsWith("a")
LIKE '%a' => EndsWith("a")
LIKE '%a%' => Contains("a")
LIKE 'a%b' => StartsWith("a") && EndsWith("b")
LIKE '%a%b%' => StartsWith("a") && Contains("b")
You do not need to use percent sign while filtering. e.g;
if I want to check ItemName does not contain '-' I will do it like this
!Item.ItemName.Contains("-")
In SQL it will convert to NOT LIKE '%-%'
We use Database First and the EntityFramework.
The "Map your own function." approach works for us together with the nuget EntityFramework.CodeFirstStoreFunctions.
1 Step: Create a function in the db like this:
CREATE FUNCTION [dbo].[StringLike]
(
#a nvarchar(4000),
#b nvarchar(4000)
)
RETURNS bit
AS
BEGIN
RETURN
(SELECT CASE
WHEN (SELECT 1 WHERE #a LIKE #b) = 1 THEN 1
ELSE 0
END)
END
2 Step: Install nuget EntityFramework.CodeFirstStoreFunctions
3 Step: Create a method in your code like this (I create mine in the DbContext class):
[DbFunction("CodeFirstDatabaseSchema", "StringLike")]
public static bool Like(string input, string pattern)
{
throw new NotSupportedException("Direct calls are not supported.");
}
4 Step: Initalize EntityFramework.CodeFirstStoreFunctions.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType()));
}
5 Step: Now you can use this method in your linq query.

Categories

Resources