Equals() is insensitive to letter cases in LINQ - c#

I have recently been learning LINQ queries to the database. I have encountered quite a weird problem. In my query I am trying to compare 2 strings with the Equal() function. I use the ToUpper() function to have one string in upper case and compare it to the same one but in lower case. The Equals() function is sensitive to the cases of letters, which I checked outside of the query, but the Equals() in the query returns the "true" value. It is really a stupid error, but I really checked if it should work like that and if I didn't make a mistake. I write in C#, work in Visual Studio 2022 and connect to the SQLServer database through the Entity Framework. I am going to put my code below:
var wynik = from pracownik in Context.Pracownik
let P = pracownik
let stan = P.stanowisko.ToUpper()
where stan.Equals("informatyk")
select new
{
id_pracownika = P.id_pracownika,
nr_departamentu = P.nr_departamentu
};
foreach (var prac in wynik)
{
Console.WriteLine(prac.id_pracownika + " " + prac.nr_departamentu);
}
Basically the Equals() function returns true to "informatyk"=="INFORMATYK", but only in the LINQ query. Does someone know what the problem is?

LINQ to Entities doesn't perform the actual comparison. Instead, it translate your statements to SQL (or whichever language your database uses) and lets the database worry it.
Depending on which database that you're using, that SQL will look similar to this:
SELECT id_pracowinka, nr_departamentu
FROM Pracownik
WHERE UPPER(stanow) = "informatyk"
By default, SQL Server use case-insensitive collation. (Many other databases such as Oracle and PostgreSQL are case-sensitive by default.)
This can be modified on the tables itself and is probably going to be your easiest way to handle this.
If instead, you'd like LINQ to Entities to render the SQL differently, you'll want to brush up on Expression Trees.
https://learn.microsoft.com/en-us/dotnet/csharp/expression-trees

SQL server is by default case insensitive. LINQ converts your C# expression tree to a SQL query with Equals mapped to ordinary equality checks in SQL Server. As those checks are case insensitive, you get the behavior you see here.

Related

Difference between lamda where condition and linq where condition?

I am working with MVC Core with EF-6.x and I am using Lambda expression, but my senior told me use LINQ why, because while using lambda with where clause it will pull all the data from database and later it will apply where condition. In case of LINQ if you use where condition it will pull only filtered data. Please let me know what is correct?
e.gLambda: context.tablename.where(condition);// Should I go with this
LINQ: (from T in tablename where t.(condition));// or this?
Please let me know what is correct?
e.gLambda: context.tablename.where(condition);// Should I go with this
LINQ: (from T in tablename where t.(condition));// or this?
Short answer: it doesn't really matter. Since context.tablename ultimately returns an IQueryable<T>, Entityframework will not try to hit the database until you try to iterate the final result from your expression, not to mention, .ToArray() and .ToList() each, does that iteration for you.
Either you used LINQ expression syntax (which gets compiled as LINQ methods) or LINQ methods, when you attempt to begin iterating the results, Entityframework creates an Expression tree for you underneath the hood that consists of your query altogether (including Wheres, Joins, GroupBys, etc). Since the structure of a LINQ might not percisely match the structure of a SQL query (or whatever data-source query), depending on the source (i.e database, e.g SQL Server), Entityframework then attempts to make the best possible optimization to your expression tree so that its structure would match an executable query on the source (e.g SQL Server query). Finally, it translates that expression tree into an actual query and executes it against the data source, and return your data (after doing all the mapping of course).
If you really, and I mean REALLY want to go through the complications of how an IQueryable engine works, I'd suggest taking a walk through Matt Warren's series: 'LINQ: Building an IQueryable provider series'. That's not actually Entityframework but it shares the same concept.
Both syntax will be translated into the same IL code. The difference, if the filter will be applied on server or client side is, if the source is IQueryable<T> or IEnumerable<T>.
my senior told me use LINQ why, because while using lambda with where
clause it will pull all the data from database and later it will apply
where condition.
Your senior is wrong, you can use the statement you prefer they are the same, both will filter the data at database level. If you have Sql Server as database server, you can use Sql Server Profiler to dump the queries executed by both statements and you will see that they are the same.

Linq Check if a string contains any query from a list

I have a list of strings that are search Queries.
I want to see if a string from the database contains anyone of those terms in the Query. I'd like to do this on one line of code, that doesn't make multiple calls to the database. This should work but I want it to be more optimized.
var queries = searchQuery.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries).Distinct();
var query = context.ReadContext.Divisions.AsQueryable();
queries.ForEach(q => {
query = query.Where(d => (d.Company.CompanyCode + "-" + d.Code).Contains(q));
});
Is there a function that can do this better or a more optimal way of writing that?
There are two issues with your proposed solution:
Most LINQ to SQL providers don't understand string.Contains("xyz") so the provider will either throw an exception or fetch all the data to your machine. The right thing to do is to use SqlMethods.Like as explained in Using contains() in LINQ to SQL
Also, the code you show will check whether the division contains all of the specified strings.
To implement the 'any' behavior you need to construct a custom expression, which will not be possible using plain C#. You would need to look at the System.Linq.Expressions namespace: https://msdn.microsoft.com/en-us/library/system.linq.expressions(v=vs.110).aspx
It is possible, but quite involved.

Use a NaturalSortComparer in a LINQ Where Clause

Say I have a table Table1 with a string field [ProductString] with values:
Alpha, alphanumeric or numeric: eg ABC, B4, U2, C 5, 100, U1, U5, U6, U11
I want to be able to take a where clause like "ProductString >= U5", and pass this to a LINQ statement as a string so it evaluates
Table1.Where(t=> t.ProductString >= 'U5');
Normally this would return results U5 and U6.
However, this I want to be able to use a NaturalSortComparer somehow so that the results returned are U5, U6 and U11.
I know how to use the comparer in an OrderBy, by I wanted to be able to use it at the Where stage.
Using natural sort comparer:
var comparer = new NaturalComparer();
Table1.Where(t=>
comparer.Compare(t.ProductString, "U5") >= 0);
Presuming all your product strings is on the format U%number% then why not abuse that fact?
Table1.Where(t=> int.Parse(t.ProductString.Replace("U","")) >= 5);
If you're using LINQ to Entities I'm not certain this will compile to a store expression (i.e that SQL knows what to do with this - I guess it should).
I'm a little confused, given the accepted answer, about whether this question relates to LINQ to Entities or not. The accepted answer doesn't appear to be a solution that would work in the LINQ to Entities context, but the comments on the question by the OP seem to confirm that this is being executed in the database context. Anyway, this answer is specifically targeted toward LINQ to Entities.
I think doing this in SQL Server would be hard, but not impossible. The problem is that .NET knows what NaturalSortComparer is, but SQL Server (where you want the query to ultimately take place) has no such concept. The best idea I can think of would consist of 2 parts:
Create a UDF (User Defined Function) in SQL server that will give a product that is orderable via natural sort: CREATE FUNCTION Naturalize(#val as nvarchar(max)) RETURNS nvarchar(1000). There's a pretty cool answer here that creates a UDF wrapper around a CLR function to accomplish just that.
Next create a function mapping for your DbContext that maps the UDF above to a function that can be called inside an EF query against the DbContext. Something like this:
[DbFunction("MyContext", "Naturalize")]
public static string Naturalize(this string value)
{
throw new NotSupportedException("This function can only be invoked from LINQ to Entities.");
}
Once you've got these two pieces in place, you can readily use this new function inside an entity query to compare strings using the Naturalized value in the comparison:
Table1.Where(t=> t.ProductString.Naturalize() >= "U5".Naturalize());
Bear in mind that the UDF will be executed against every row contained in the query, which is the whole table in the above example. You'll want to make sure to pare down your query to something manageable before applying the function as a sub-query. Or you may want to try applying some type of UDF-based index on the table in question.
If you are going to be doing searches like this a lot, then what will be the best thing to do is add two new fields to your table, [ProductCode] & [ProductNumber] which separate the two parts of the [ProductString].
Then you comparison becomes:
Table1.Where(t=> t.ProductCode == "U" && t.ProductNumer > 5);

Expressions in Linq Query

I recently found out that i cannot call any methods from within a linq query. I am trying to write a query that, on the where clause compares two byte arrays. The value on the database is a GUID of type Raw(32) and it is returned as a byte array. This is the record ID for this table. I need to compare it to another byte array. the second byte array could be converted to a string but since i cannot call methods from within linq i was unable to compare.
I tied a custom "Compare" method, i also wrote an extension method. All received an error indicating "LINQ to Entities does not recognize the method"
Here is the code for what i am trying to do. The where clause causes this error:
LINQ to Entities does not recognize the method 'Boolean SequenceEqual[Byte] (System.Collections.Generic.IEnumerable1[System.Byte], System.Collections.Generic.IEnumerable1[System.Byte])' method, and this method cannot be translated into a store expression."
EPSGEntities dbContex = new EPSGEntities();
byte[] byteArray = ParseHex(ViewState["itemID"].ToString());
var q = (from d in dbContex.EPSG_VSOREJECTS
where d.SDSRECID.SequenceEqual(byteArray)
select d).First();
What version of EntityFramework are you using? On EF6 I am able to simply do the following against a SQL 2012 table with a varbinary column:
var q = dbContext.EPSG_VSOREJECTS.FirstOrDefault(e => e.SDSRECID == byteArray);
Is the SDSRECID property on EPSGEntities of type byte[]?
The alternative here would be to go to straight Sql to get your object. Something like:
dbContext.Database.SqlQuery<EPSG_VSOREJECT>("SELECT TOP 1 *" +
"FROM dbo.EPSGEntities" +
"WHERE SDSRECID = #byteString",
new SqlParameter
{
ParameterName = "byteString",
Value = ViewState["itemID"].ToString(),
}).FirstOrDefault();
Linq to Entities in EF is awesome for most queries, but I sometimes drop into sql when I need to do something unsupported, complex, or just fast. Hope this helps!
I'm not entirely sure this works, but I've found calling .AsEnumerable() on the IQueryable object set lets me apply pretty much any code I wish:
var q = dbContex.EPSG_VSOREJECTS.
.AsEnumerable()
.Where(d => d.SDSRECID.SequenceEqual(byteArray));
Doing so seems to prevent EF from trying to translate the Where() clause into SQL syntax, but I have no real idea what the performance hit would/will be.
This is also using method syntax, since I'm not real familiar with query syntax. HTH.
EDIT:
As some others have noted, you have to be careful with how you add any of the iterative methods (AsEnumerable(), ToList(), etc.) since past that point you are no longer building SQL against your data store. Once you start iterating, EF will execute whatever query has been built up to that point, and from then on you are filtering the result set from the LINQ query.
In this case, I don't know that this can be avoided, unless someone can build the same query as a sproc (which EF can execute on your behalf).

How to pass dynamically-generated search criteria to LINQ

I have some trouble with LINQ. In my program I generate a SQL search query like
select * from emp "where empId=1 and empname='abc'"
(where the quoted text is generated in my code). I can pass the generated "where empId..." string text to the SQL query.
I'd like to do the same thing in LINQ - I want to pass this string as the search criteria i.e. something like
var employee=from a in Employee.AsEnumerable()
"where empId=1 and empname='abc'"
select a;
Is this possible? Thanks in advance.
You can take the base query (in your case Employee.AsEnumerable()) and use the logic you use to generate the string to compose a new query. For example:
if(/*your logic for generating the string "where empId=1" here*/)
{
query = query.Where(a.empId == 1);
}
if(/*your logic for generating the string "empname='abc'" here*/)
{
query = query.Where(a.empname == "abc");
}
The resulting query object will have all the operators composed. However as others have said this is not trivial in the general case. It is not trivial with SQL strings either. If all you need to generate are several filters it will work but if you need complex expressions it will be a problem.
101 LINQ Samples
It's pretty hard, unless you intend to employ:
Dynamic code compilation, or
You are willing to create a (very complicated) parser to analyze the query and call the respective linq extension methods
I personally have no experience in the latter. As for the former, it is a bit tricky and can go nastily wrong if you don't do proper caching and security checks. Executable code injection is very dangerous.
I think you had better use different methods to filter content using methods like Where() if the number of queries can be predetermined or return to SQL if not. Usually you don't need to do this unless the query is manually entered by the user.

Categories

Resources