MySql Linq-Entities Date Comparison - c#

I am trying to do the following in MySql but get a linq-to-entities exception that the functions are not supported. I've tried using SqlFunctions.DateAdd unsuccessfully. The only solution so far is to use a ToList() but that brings it all to the client which I don't love:
var expiredPolcies = context.ApiUsagePolicies
.Where(u => DateTime.UtcNow > u.UsagePolicyStart.AddSeconds(u.UsagePeriodSeconds));

SqlFunctions is specific to Entity Framework and SQL Server.
SqlMethods is specific to Linq to SQL and SQL Server.
If there's an equivalent set of methods for MySql then you could use that.
Alternatively try rewriting your query so that there are no local methods involved. Try something like:
var expiredPolcies = context.ApiUsagePolicies
.Where(u =>
(DateTime.UtcNow - u.UsagePolicyStart).TotalSeconds > u.UsagePeriodSeconds);
It all depends on what functions your Linq provider supports.

Related

StringComparison.InvariantCultureIgnoreCase cannot be translated while used in a LINQ query

I am facing a problem executing the below query in .NET 6.
query = context.Where(user =>
user.Email.Contains(model.Email,
StringComparison.InvariantCultureIgnoreCase));
After searching the web I understood that EF Core does translate Contains for server-side evaluation - but not the overload that accepts StringComparison.InvariantCultureIgnoreCase or any other StringComparison. But never found the correct way to solve this issue
So I changed the query to something as follows to make it work:
query = context.Where(user =>
user.Email.ToLower().Contains(model.Email.ToLower());
Even though it is working I am not entirely happy with this solution and still wondering which solution solves my problem best. Would using ToLowerInvariant() be a better solution? Any better approach to solve this?
UPDATE
ToLowerInvariant() does not work and causes the same error caused by StringComparison.InvariantCultureIgnoreCase
It seems like your are writing your LINQ query on a DbSet. This is not possible as it cannot be translated to SQL statements.
You could however use the EF.Functions.Like function. This gets translated to the SQL provider and is by default case insensitive.
query = context.Where(user =>
EF.Functions.Like(user.Email, model.Email));
How your query reacts depends on the collation you set on the server side. After all your linq expressions will be translated into an SQL query and how that is interpreted will depend on your database and column settings.
What you could try is stating a collation in your query e.g.
var customers = context.Customers
.Where(c => EF.Functions.Collate(c.Name, "latin1_general_ci collation") == "John")
.ToList();
//SQL_Latin1_General_CP1_CI_AS for SQL Server
//latin1_general_ci collation for MySQL
as found in the Microsoft documentation. Where CI stands for case-insensitive (opposed to CS). Be aware that this query won't be able to leverage the index on the Name due to the custom collation. So it would be better to define it on the column (or table/database).
Try this:
query = context.Where(user => EF.Functions.Collate(user.email,
"SQL_Latin1_General_CP1_CI_AI").Contains(model.Email));

LINQ Correlated SubQuery throws Oracle Exception: Oracle 11.2.0.4.0 does not support APPLY

Here is the c# query:
qry = qry.Where(comment => idsArr.Any(
selectedId => dbv.VW_STAKEHOLDER_TYPE_XREF.Where(xref => xref.STAKE_ID == comment.STAKE_ID && xref.STAKEHOLDER_TYPE_ID == selectedId).FirstOrDefault() != null
));
From the language of the exception I am guessing that something in the c# is being translated to an apply which Oracle 11 doesn't like for some reason. I am not sure which part of the query is getting translated into APPLY and how I can circumvent this issue.
Thanks in advance.
LINQ to SQL only really works with SQL Server, although some simple queries may work on other databases. In this case the query failed as Oracle does not have a CROSS APPLY clause, but uses lateral joins instead. See this post for options when you want to use LINQ with Oracle: Is there a Way to use Linq to Oracle

Compare Greek (or other non-latin) strings in linq

I am trying to write a query in linq that returns results like this:
PeopleEntities pe = new PeopleEntities();
String fName = "Τάκης";
var people = pe.Person.Where(per => per.FirstName.Equals(fname)).ToList();
When I dump the query using
String query = ((ObjectQuery)pe.Person.Where(per => per.FirstName.Equals(fname))).ToTraceString();
Console.WriteLine(query);
and then using the query in a MySQL WorkBench providing a value, everything works fine but in code the query returns nothing.
Edit: I have connected entity manager by using a MySQL connector. I hadn't thought about it earlier but this is the problem as with an MsSQL connection everything works fine
Any ideas on how I can execute the above?
In a regionally-sensitive query, you should not use string.Equals() without providing a StringComparison value, e.g.:
var people = pe.Person.Where(
per => per.FirstName.Equals(fname, StringComparison.CurrentCultureIgnoreCase));
Yes, this overload is supported in L2E.
If that still does not work, it is possible that the AppDomain's current culture or the DB's collation is wrong. Look at the query/params in SQL Profiler.

How do I view the SQL generated by SubSonic SimpleRepository?

I've got this toy code, works fine, using MySQL
var r = new SimpleRepository("DB", SimpleRepositoryOptions.None);
var q = r.Find<User>(x => x.UserName == "testuser");
How do I view the SQL generated by that query ?
For SQL Server, you can always run SQL Profiler to see the queries.
Unfortunately using SimpleRepository you can't do what you want without stepping into the SubSonic code. Because the Find method returns an IList it's executed before you get the chance to evaluate the SQL that's going to be executed. There are efforts underway to add this functionality in future versions of SubSonic but until then you're probably best looking at the MySQL Query Profiler.

How to Use Dates in Where Clause in EF Core?

I need to filter my queries by dates but I don't care in this case about time portion of it that is stored in SQL Database.
I first tried to something like
var now = DateTime.Now.Date;
Where(x => x.CreatedDate.Date.Compare(now) == 0)
but this seems to all get locally checked making the query slow. How can I do this without making it do the check locally?
I am pretty much trying to just find all results that would say have happened today(2020-01-06).
There are a limited number of methods you can use on translatable types when constructing your Lambda / Linq expressions. This is because each method would need additional code so that it could be translated into a sql store expression. It means that you must check that any methods you want to use and expect to be translated into a sql store expression are supported.
In this case the DateTime.Compare is not supported.
The easiest thing to do here is a simple range comparison because the time is included in your persisted value.
var start = DateTime.Now.Date;
var end = start.AddDays(1);
Where(x => x.CreatedDate >= start && x.CreatedDate < end)
This will result in a sargable query.
Use
var now = DateTime.Now.Date
...WHERE(CreatedDate.Date == now)
I just checked that above translates to the following SQL query:
WHERE ((CONVERT(date, [x].[CreatedDate]) = '2019-01-07T00:00:00.000')
I used this (link) method to see what LINQ translates to

Categories