How to set Turkish collation on postgres database using EF code first - c#

my database records have strings with Turkish "İ"
and I have the linq query like below:
query=query.where(r=>r.User.FirstName.ToLower().Contains(fullName.ToLower())
in the database I have user with name of "İbrahim"
searching about fullName=İbrahim gives me right result
searching about fullName=ibrahim gives me wrong result
first I tried to send culture info inside linq query like this:
var culture = new CultureInfo("tr-TR", false);
r.User.FirstName.ToLower(culture)
but having culture info inside database connected LINQ query gives exceptions
then
I tried to define my postgres database with Turkish collation throw EF like this:
modelBuilder.UseDatabaseTemplate(“template0”);
modelBuilder.UseCollation(“C”);
modelBuilder.Entity().Property(p => p.Name).UseCollation(“tr-TR-x-icu”);
modelBuilder.UseTablespace(“pg_default”);
but I got this exception:
pg_default LC_COLLATE "C"; Npgsql.PostgresException (0x80004005):
22023: new collation (C) is incompatible with the collation of the
template database (English_United States.1252)
any solutions ?

Related

Is it possible to use Linq .IndexOf() in SQL Server database ? - Alternative to .Contains()

Does anyone know a way to use/ if its possible
.IndexOf()
in SQL Server instead of
.Contains()
Currently I get a NotSupportedException:
The translation of String.IndexOf to SQL does not support versions with a StringComparison argument
I would like to have something better performing than .Contains(ToLower(string)).
This is what I tried:
.Where(b => b.item.IndexOf(boSearchTerm, StringComparison.CurrentCultureIgnoreCase)!= -1)
The concept of StringComparison cannot be translated to SQL because databases use more specific concept of collations. To do a case insensitive comparison, use a case insensitive collation at storage (instance, database or column definition) or force a specific collation in the comparison, see Casting Collation of an Expression. The collation to be used is entirely specific on the national type of the data used.
Also, using ToLower() is incorrect in C# and in any other language of choice. It will not pass the Turkish I test.
Set the collation of your column to CI (case-insensitive) and the Contains will be case insensitive... – Wouter Huysentruit 1 min ago
The easiest way to ignore casing in your SQL queries is to set the collation of the column to CI (case-insensitive), that way Contains or any other string comparison will be case-insensitive.
If you want to improve this lookup, you can also add a FULLTEXT INDEX on the column.

Linq query not behaving as expected

I have a very simple linq query which is as following:
var result = (from r in employeeRepo.GetAll()
where r.EmployeeName.Contains(searchString)
|| r.SAMAccountName.Contains(searchString)
orderby r.EmployeeName
select new SelectListItem
{
Text = r.EmployeeName,
Value = r.EmployeeName
});
The issue is for some strange reason it fetches me the record of every person who I search for whether in lower case or upper case. i.e.
test user
Test User
TEST USER
I will get back the correct records. However when I search for my own name using lower case I don't get any results back but if I use the first letter of my name as upper case then I get the results. I can't seem to figure out why its doing that.
Every first and last name in the database start with upper case.
The searchString which I'm using are:
richard - I get correct results
waidande - no results found
Both of the above users are in the database.
I'm also using Entity Framework to query Sql Server 2012.
If your text has NVARCHAR datatype check for similiar letters that in reality are not the same:
CREATE TABLE #employee (ID INT IDENTITY(1,1), EmployeeName NVARCHAR(100));
INSERT INTO #employee(EmployeeName) VALUES (N'waidаnde');
SELECT *
FROM #employee
WHERE EmployeeName LIKE '%waidande%';
-- checking
SELECT *
FROM #employee
WHERE CAST(EmployeeName AS VARCHAR(100)) <> EmployeeName;
db<>fiddle demo
Here: 'а' != 'a'. One is from Cyrillic 'a' and the second is normal.
Idea taken from:
Slide from: http://sqlbits.com/Sessions/Event12/Revenge_The_SQL
P.S. I highly recommend to watch Rob Volk's talk: Revenge: The SQL!.
To troubleshoot the issue, determine whether the problem is on the EF side, or on DB side.
A common mistake is extra whitespace, so make sure it's not the case before proceeding.
First check what query is being generated by EF, you can use one of the following methods to do this
ObjectQuery.ToTraceString() method
EF logging of intercepted db calls
Sql server profiler
If you are using EF correctly and your query is translated to SQL as expected and contains the predicates in the where section, but you still are not getting any meaningful results, here are some ideas to try out on the DB side:
Check collation ( be aware it can be set on server, database and individual column level) - beware of case sensitivity and code page that is being used
Verify that your search string contains symbols that can be interpreted in the db code page - for example if code page is 252 - Windows Latin 1 ANSI and you are sending input with symbols from UTF-16 that are outside ANSI - you won't get any results, even though the symbols look the same
Highly improbable, but as last resort check if one of your queries has not been cached, as described here
SQL Server 2012 (SQL Server) is installed by default with case insensitive collation. If you need to retrieve records from the database using case sensitivity (because you have "several" records) you need to change the collation (take care because if you change DBMS collation you change also master database collation so also tables and field names become case sensitive).
If you don't need to avoid to retrieve all the records from the DBMS you can just filter records after you retrieve them, i.e.
var result = (from r in employeeRepo.GetAll()
where r.EmployeeName.Contains(searchString)
|| r.SAMAccountName.Contains(searchString)
orderby r.EmployeeName
select new SelectListItem
{
Text = r.EmployeeName,
Value = r.EmployeeName
})
.ToList() // Materialize records and apply case sensitive filter
.Where(r.EmployeeName.Contains(searchString)
|| r.SAMAccountName.Contains(searchString));

Dapper throws exception second time you run a query if different results schema

I'm using Dapper, Sqlite on c# coreclr.
public async Task<UserPoco> GetFromEmail(string email)
{
email = email.ToLower();
using (var connection = new SqliteConnection(_configSettings.ConnectionString))
{
connection.Open();
var query = $"SELECT * FROM users WHERE EmailAddress = '{email}';";
var result = await connection.QueryAsync<UserPoco>(query);
return result.FirstOrDefault();
}
}
That simple method throws an exception if at some point the SQL query find no results and next time it runs it does find results.
It throws:
Unable to cast object of type 'System.Int64' to type 'System.Int32'.
Error parsing column 0 (UserId=86 - Int64)
I'm pretty sure it's not related to the Datatypes. The UserPoco has a long UserId property and the DB table users has a UserId of type INTEGER which is the recommended one to store bigint (long). Moreover, for example if the method always finds data it will work like a charm.
I do think is related to the fact that Dapper caches the result schema of every query it runs and throws an exception when this schema changes for the same query as they point out on:
https://github.com/janjosephlim/dapper-dot-net/issues/124
What I don't understand is how come I can't find more info about this or more people is complaining about such a common scenario: I'm just running a very simple query multiple times which can bring back or not results.
What am I missing?
I don't know why sqlite is misreporting the data type, but: the data type checks have been improved in recent pre-release builds. Please check with the latest pre-release build: I expect it is already fixed.

Lightswitch - C# LINQ Preprocess Query

I'm pretty new to LINQ and I'm having trouble restricting the number of values (strings in "yyyy-mm" format) from my "Availabilities" entity which are shown on a Lightswitch screen, based on a Query ("LINQ_Query"). The idea is to show only "Availabilities" which are recent - for example where int.Parse(av.Availability.Substring(0,4)) > 2013
The reason I'm doing this is that "Availability" entity contains strings and not all of them are in "yyyy-MM" format - there are also entries like "Available", "Delayed", "2014" etc. I want to filter only the ones which have a length of 7 and ideally are more recent than 2013-12 and not in the future (Availability > current date).
In SQL I have achieved this with the following code:
SELECT Availability FROM Availabilities where LEN(Availability)=7 and LEFT(Availability,4) > 2013 and availability<=CONVERT(varchar(7),GETDATE(),126) order by Availability desc
The C# code I use for my PreprocessQuery is the following and it compiles with no errors:
partial void LINQ_Query_PreprocessQuery(ref IQueryable<Availabilities> query)
{
query = from av in query
where av.Availability.Length==7 && int.Parse(av.Availability.Substring(0,4)) > 2013
select av;
}
However, when I deploy and test there are the dreaded red Xs on the screen in question. I enabled tracing and I see the error is:
[Microsoft.LightSwitch.DataService][Application:Error][LightSwitchApplication.ApplicationData:LINQ_Query] An exception has occurred: Microsoft.LightSwitch.DataServiceOperationException: LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression.
Is there a workaround for this? I was thinking of executing a separate "IDataServiceQueryable" query and then pointing the Preprocess IQueryable query to the results of the "IDataServiceQueryable" one. Is there any chance this or another type of query would work with int.Parse or DataTime.Parse/ParseExact?
Thanks in advance!
P.S. Some more details about my setup: I'm testing a Web Lightswitch 2011 application, hosted on my PC as IIS Server. The Database is hosted on a SQL Server 2008 Express x64 SP3 also on my PC, which leads me to anothe question - since LINQ to Entities doesn't support the functions I need, can I create a LINQ to SQL query on the Availabilities table?
Try splitting them up and removing the cast
partial void LINQ_Query_PreprocessQuery(ref IQueryable<Availabilities> query)
{
query = query.Where(x=>x.Availability.Length==7);
query = query.Where(x=>x.Availability.Substring(0,4) == "2013";
}
Ctype or Parse in Linq could be trouble (if it would fail for one, it fails for all)
If it works, join the 2 queries again.

string length failing in Azure using LINQ

I having issues with SQL Azure, the following LINQ with EF code works fine if the database is SQL Server 2012
var userLength = users.Select(n => new { n.FirstName.Length });
But, if I point it to an Azure database and I get
"base = {"The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."}"
Any ideas?
Do the databases contain same data?
Maybe one of users has no FirstName set in Azure database?
I guess it's when you iterate over usersLength that you receive this Exception? Is it thrown on first iteration or maybe later?
Here's what I think is happenning (I'm using LINQ to Objects here)
You can edit it like this to make it return 0 for null elements (FirstNames):
You can download those two code snippets if you have LinqPad here (they will be automatically opened in LinqPad):
http://share.linqpad.net/2pfjqf.linq
http://share.linqpad.net/vp96kf.linq

Categories

Resources