0

By default ODataController performs case-sensitive search. How do we extend this behaviour to perform case-insensitive search.

public class NammaODataController : ODataController
{

    [EnableQuery]
    public IQueryable<FD> GetFD(ODataQueryOptions qo)
    {
        return _ctx.FDs.AsQueryAble();
        //EF takes care to apply odata query operators internally 
        //after control passes from action
    }
}

I referred this SO seems we can leverage Expression Tree, but at which extensiblility point?

Is there any way I could intercept the query and customise EF / Web Api piplelie to achieve this?

Here's an example: /FD?$filter=tolower(Pr_Name) eq tolower('TAMARA') - this should return all people with name 'Tamara' (case insensitive, could be 'TAMARA', 'tamara', 'Tamara', etc. Hope this will help, to put forward my point.

EDIT:

Case-senitivity in ODATA Web API queries has nothing to do with SQL Collation. This has been an issue with Microsoft OData framework.


With substringof operator

void Main()
{
    var lower = _ctx.FD
    .Where(sv => sv.Pr_Name.Contains("tamara"))
    .Take(1)
    .ToList();
    Console.WriteLine("LOWER CASE AZURE SQL OUTPUT");
    Console.WriteLine(lower);

    Console.WriteLine("UPPER CASE AZURE SQL OUTPUT");
    var upper = _ctx.FD
    .Where(sv => sv.Pr_Name.Contains("TAMARA"))
    .Take(1)
    .ToList();
    Console.WriteLine(upper);
}

enter image description here


With eq operator

void Main()
{
    var lower = FD
        .Where(sv => sv.Pr_Name == tamara A TOPOLESKI")
        .Take(1)
        .ToList();
    Console.WriteLine("LOWER CASE AZURE SQL OUTPUT");
    Console.WriteLine(lower);

    Console.WriteLine("UPPER CASE AZURE SQL OUTPUT");
    var upper = FD
        .Where(sv => sv.Pr_Name == "TAMARA TOPOLESKI")
        .Take(1)
        .ToList();
    Console.WriteLine(upper);
}

enter image description here

Abhijeet
  • 13,562
  • 26
  • 94
  • 175
  • 1
    Are you certain this isn't the database? a quick way to check a field is to write: "sp_help FD" then in the collation has a _CS_ it is case sensitive. I have never tried where it was OData that decided this. – Thomas Koelle Nov 01 '17 at 14:42
  • @ThomasKoelle, IMHO DB collation will not help as ODATA is in command here, even if we turn DB tables to perform `Case-Insensitive` ODATA pipeline will convert it into Case-Sensitive filter – Abhijeet Nov 02 '17 at 05:27

1 Answers1

1

Edit

You are right, the problem is not related to your collation. It has to do with the odata expression that you are using. In your updated test query you are using Contains which gets translated into a LIKE with wild cards (any string of zero or more characters) at either end of the search value. However, in your odata expression you are using eq which will get translated into a = in EF expression and then again in the SQL query. As the Pr_Name values you have shown in your output are not exactly equal to "Tamara" but contain "Tamara" the odata queries will not bring back any data.

What you need is the odata filter expression substringof which would get translated by EF to Contains which is translated in sql to LIKE with wild cards on either side of the search value.

/FD?$filter=substringof(Pr_Name,'tamara')

For more filter expressions refer to Using Filter Expressions


As @ThomasKoelle stated in the comments this has to do with the collation of the column(s). The OData pipeline (you have defined above) uses Entity Framework which converts the passed in expression into a query for the database. So the OData expression has nothing to do with it and neither does the built EF query.

If you have a case sensitive collation then you would have to make all your search terms and search columns the same case which is very bad for performance because those search clauses would not be SARGable.

For most DBMS's the collation of the column is inherited from the default collation of the database which is inherited from the instances default collation. You can override at each level but it must be done explicitly at the time the instances (schema / database) are defined.

Igor
  • 60,821
  • 10
  • 100
  • 175
  • thanks @Igor, I have confirmed with MS, `The default collation of Azure SQL DB is - SQL_Latin1_General_CP1_CI_AS. This indicates Case Insensitive collation`. -- AFAIK No action needed on collation. – Abhijeet Nov 02 '17 at 13:34
  • @Abhijeet see my update and please take a look at the added link, this might be directly related to your issue. – Igor Nov 02 '17 at 13:43
  • @Abhijeet - I updated my answer, this should work for you also based on your previous test and shown output. – Igor Nov 03 '17 at 08:56
  • Contains I just took as an example, SQL has been case-insensitive to even `eq` operator. thanking you. – Abhijeet Nov 03 '17 at 11:52