Linq query translation to SQL messes up null parameter values - c#

Here's a simple LINQ query:
var objs = db.Objects.Where(o => o.Field1 == val);
This translates to SQL query:
select * from [Object] where Field1 = #p1
Trouble is, the value of val can also legitimately be null. And SQL doesn't like comparing nulls; it insists on the syntax ... where Field1 is null.
Is there any way of doing this neatly, short of using a ?? / isnull operation?

This, again, is an EF weakness in LINQ support. Good old LINQ to SQL translated this properly depending on the runtime value of val.
I suggest you go with this:
var objs = db.Objects.Where(
o => (o.Field1 == val) || (o.Field1 == null && val == null));
If EF translates this litterally, the SQL Server query optimizer will actually pick up this pattern and optimize it to an "equals-with-nulls" check. You can even seek indexes using this code pattern, it just works. In the query plans this shows up as IS in contrast to EQ.

How about .HasValue?
var objs = db.Objects.Where(o => !o.Field1.HasValue && o.Field1 == val);

Related

LINQ is converting string to special characters

I am using this query to get data from database.
string nfc = "53f8372c";
var temp = db.tempTable.AsNoTracking().Where(
x =>
x.uid.Equals(nfc, StringComparison.CurrentCultureIgnoreCase)
&& x.ENDED == null
&& x.STATUS.Equals(Constants.ACTIVE)
);
The sql that is generated from this query is:
{SELECT
"Extent1"."ID" AS "ID",
"Extent1"."uid" AS "uid",
"Extent1"."ENDED" AS "ENDED",
"Extent1"."STATUS" AS "STATUS",
FROM "tempTable" "Extent1"
WHERE (("Extent1"."uid" = :p__linq__0) AND ("Extent1"."ENDED" IS NULL) AND ('Active' = "Extent1"."STATUS"))}
Why does it convert 53f8372c to :p__linq__0?
That's just parameterizing the SQL. If you look at the parameters passed to the query, you'll see that :p__linq__0 has a value of 53f8372c.
This parameterization is helpful, as the server can cache the query plan and reuse it for the same query using different parameter values.

changing linq to sql query

I have a question regarding a Linq to SQL query.
I have following situation:
I have a search with lots of options, like location, availability, name, language etc ...
For this options i have to execute a query to retrieve the results according to options selected, how can i best do it, i cannot write a linq query like for each possibility and combination of options, but i cannot write one for all of them as it will not work, for example:
from p in context.people where p.location==model.location && p.availability==model.availability .... select p
In this case imagine availability is not selected and should not be searched for, but in this case it will be passed as false, or if location is not set and is null so it will only search for empty locations, although i just need all.
So my question is how do people handle this kind of behaviour with queries?
As you long as you do not execute the linq query immediately you can just add where clauses to it. You can do this for example:
var query = from p in context.people;
if(searchOnLocation)
{
query = query.where(p => p.location == model.location);
}
if(otherSearch)
{
query = query.where(p => p.someOtherProperty == someotherValue);
}
var result = query.ToList();
As long you don't call ToList() on your IQueryable, the linq will not be translated into SQL. It's only in the last call, that the linq will be translated and executed against the database
IQueryable<Person> query = context.people;
if(model.location != null)
query = query.Where(x => x.location == model.location);
if(model.availability != null)
query = query.Where(x => x.availability == model.availability);
// etc
Basically, you can compose more and more restrictions as you go.
If you want to implement query without if condition than you can use following syntax:
var query = context.people.
where(p => p.location == (model.location ?? p.location)
&& p.availability == (model.availability ?? p.availability))
.ToList();

Null coalesce not working in LINQ query

Take this:
int? item1 = null;
int? item2 = null;
someObjectList.Where(x => x.SomeItem1 == (item1 ?? x.SomeItem1)
&& x.SomeItem2 == (item2 ?? x.SomeItem2)
);
Where someObjectList is not empty and SomeItem1 and SomeItem2 is null in all the objects in the list.
Why is it returning nothing?
EDIT:
My Code:
public void GetPlacementsByMaterial(long clientMaterialID)
{
ClientMaterial clientMaterial = ((ApplicationEntityModel)NavigationItem.ObjectContext).ClientMaterial.FirstOrDefault(x => x.ClientMaterialID == clientMaterialID);
var list = GetPlacementList(supplier, mediaSpace);
PlacementsList = list.Where(x => x.MediaCategoryFormatID == (clientMaterial.MediaCategoryFormatID ?? x.MediaCategoryFormatID)
&& x.MediaCategorySizeID == (clientMaterial.MediaCategorySizeID ?? x.MediaCategorySizeID)
);
}
All ID's are Nullable<long>.
EDIT:
SQL Profiler:
SELECT *
FROM [dbo].[CampaignSchedulePlacements] AS [Extent5]
WHERE ([Extent5].[MediaCategoryFormatID] = [Extent5].[MediaCategoryFormatID]) AND ([Extent5].[MediaCategorySizeID] = [Extent5].[MediaCategorySizeID])
Note: cleaned up the `SQL.
In SQL, NULL is not equal to NULL.
You can interpret NULL as meaning: "there is value, but I don't know what it is". So if you're comparing two NULL values, you're really asking "is the first unknown value equal to the second unknown value?" Of course, there is no reason to assume they are, so SQL will say "no".
I am assuming that this is causing your problem. You can verify that by looking at the actual SQL produced. If it's using the SQL = operator, this is indeed the problem. You can verify that by running the SQL in a database tool, such as SQL Management Studio in case you're using SQL Server.
UPDATE:
The condition
([Extent5].[MediaCategoryFormatID] = [Extent5].[MediaCategoryFormatID])
will indeed return false when [Extent5].[MediaCategoryFormatID] is NULL.
That answers the question "Why is it returning nothing?"
However, another question come to mind: why would the entity framework generate that SQL from this linq query?
I'm afraid that linq to entities is not exactly known for the quality of its SQL generation, and this case seems to confirm that. You might consider Linq to SQL. Even if that seems to be a dead-end track in the long run, the current implementation if a lot better than linq to entities.
In either case, have you tried something like
someObjectList.Where(x =>
!item1.hasValue ||
x.SomeItem1.HasValue && x.SomeItem1.Value == item1.Value)
Make sure to verify that under the profiler as well though, linq to entities might mess it up too.

would it be bad practice to add select to shorten Linq query?

for example
Originally:
var query = A.Where(x=>criteriaA(x.item2).Where(x=>criteriaB(x.item2))
.Where(x=>criteriaC(x.item2))).Select(x=>x.item2);
What if:
var B = A.Select(x=>x.item2)
var query = B.Where(x=>criteriaA(x)
.Where(x=>criteriaB(x)).Where(x=>criteriaC(x)));
it's fine - what about
var query = A.Select(x=>x.item2)
.Where(item2=> criteriaA(item2)
&& criteriaB(item2)
&& criteriaC(item2));
There would be little difference and should have similar performance characteristics. I've also checked in linq pad and the resultant SQL for linq to SQL is identical
You can shorten the query further with either
var B = A.Select(x=>x.item2)
var query = B.Where(x=>criteriaA(x) && criteriaB(x) && criteriaC(c));
or
var B = A.Select(x=>x.item2)
var query = B.Where(criteriaA).Where(criteriaB).Where(criteriaC);
They produce the same result, and I expect them to have very similar performance characteristics. The second has a little less duplication, so I'd prefer that one. You might even be able to shorten it further to:
var query = A.Select(x=>x.item2)
.Where(criteriaA).Where(criteriaB).Where(criteriaC);
Or, by collapsing all the predicates:
var query = A.Select(x=>x.item2)
.Where(x => criteriaA(x) && criteriaB (x) && criteriaC(x));
Linq queries could be written in many ways, but I prefer to keep them as readable as possible.
I would prefer something like:
var query = from x in A
where criteriaA(x) && criteriaB(x) && criteriaC(x)
select x;

Handling null values in where clause using LINQ-to-SQL

The LINQ-to-SQL query in Visual Studio generates an SQL query with errors. In LINQPad, the same LINQ query using the same database (or DataContext) runs just fine.
LINQ Query
var accesDomaines = from t in db.Access
where t.IdUser == access.IdUtilisateur
where t.IdDomain != null
where t.IdRole == access.IdRole
where t.IdPlace == access.IdPlace
select t;
Here's a small part of generated SQL where the error occurs:
WHERE (...) AND ([t3].[IdRole] = ) AND (...)
After the equals in where clause, there's literally nothing ! In the SQL query of LINQPad we see the good where clause:
WHERE (...) AND ([t3].[IdRole] IS NULL) AND (...)
When I compare the two generated SQL queries from VS and LINQPad, line by line, this is the same thing. Except LINQPad is using params and also the missing right part of equal in where clause of Visual Studio, as shown before.
Note 1
In the LINQ query, I tried with this syntax in where clauses:
where t.IdRole.Equals(acces.IdRole.Value)
But also generates a bad result. I even tried something like this before the LINQ query:
if (!acces.IdRole.HasValue) { acces.IdRole = null; }
Note 2
Properties are nullable integers. I do want null in query if property is null. Obviously, I want the value of property if there's a value.
Note 3
I have tried the proposition made in this question: Linq where column == (null reference) not the same as column == null
...with no success.
Any explanation of two similar LINQ queries, but generating a good and a bad SQL query? Any suggestion to solve this problem?
Thank you!
try this:
where object.Equals(t.IdRole, access.IdRole)
Use
object.Equals()
.Net would take care of generating correct sql for null condition.
Example:
Say you have a street table with columns like Suffix and Prefix. Then following linq query doesn't work:
string suffix = "ST";
string prefix = null;
var map = from s in Streets
where s.Suffix==suffix || s.Prefix==prefix
select s;
It would generate following sql:
SELECT [t0].[StreetId], [t0].[Prefix], [t0].[Suffix]
FROM [Street] AS [t0]
WHERE ([t0].[Suffix] = #p0) AND ([t0].[Prefix] = #p1)
we can clearly see it will not return any result.
Using object.Equals():
string suffix = "ST";
string prefix = null;
var map = from s in Streets
where object.Equals(s.Suffix, suffix) && object.Equals(s.Prefix,prefix)
select s;
would generate sql:
SELECT [t0].[StreetId], [t0].[Prefix], [t0].[Suffix]
FROM [Street] AS [t0]
WHERE ([t0].[Suffix] IS NOT NULL) AND ([t0].[Suffix] = #p0)
AND ([t0].[Prefix] IS NULL)
Which is correct one.
(Little late, but wanted to expand the answer for the benefit of others)
Have you tried verifying whether your properties had values with the HasValues property provided by the Nullables?
where t.IdRole == access.IdRole.HasValues ? access.IdRole.Value : null
Perhaps this could work. I haven't used LINQ-to-SQL really.
This example worked for me:
var aff3 = from a in context.Affiliates
where ((name == null && a.CompanyName == null) || (a.CompanyName == name))
select a.ID;

Categories

Resources