Linq query works with null but not int? in where clause - c#

I have a linq query function like (simplified):
public IList<Document> ListDocuments(int? parentID)
{
return (
from doc in dbContext.Documents
where doc.ParentID == parentID
select new Document
{
ID = doc.ID,
ParentID = doc.ParentID,
Name = doc.SomeOtherVar
}).ToList();
}
Now for some reason when I pass in null for the parentID (currently only have data with null parentIDs) and I get no results.
I copy and paste this query into LinqPad and run the following:
from doc in dbContext.Documents
where doc.ParentID == null
select doc
I get back a result set as expected...
The actually query has left join's and other joins but I have removed them and tested it and get the same result so the joins are not affecting anything. The app and LinqPad are both connected to the same DB as well.
Edit: Tested with just 'null' in the appliction query and it returns the result as expected so the issue is using null vs int?. I have updated question to make it more useful to others with the same issue to find this thread.

Literal null values are handled differently than parameters which could be null. When you explicitly test against null, the generated SQL will use the IS NULL operator, but when you're using a parameter it will use the standard = operator, meaning that no row will match because in SQL null isn't equal to anything. This is one of the more annoying .NET/SQL semantic mismatches in LINQ to SQL. To work around it, you can use a clause like:
where doc.ParentID == parentID || (doc.ParentID == null && parentID == null)

You can use also something like ...
from doc in dbContext.Documents
where doc.IsParentIDNull()
select doc
It worked for me!
hope it work for you!

Related

Handling Null Exception in Linq to Sql on a binary data type column

I'm trying to get my image from my local database in wp8. Some cells in the image column contain the actual image(in a binary format) whereas others are NULL. Here is the code:
var image_professor = (from n in College.professor
where n.Surname == Getsurname(MyLongListSelector2.SelectedItem.ToString()) && n.FirstName == GetFirstname(MyLongListSelector2.SelectedItem.ToString())
select n.Pic).Single();
Everything works fine if I click on a professor which images is stored in the database,but if a professor without an image is selected then I get a NullException. Is there a way that I could use a if-else check inside my Linq query and somehow get another value if the query run's on Null or should I use another approach.
var image_professor = (from n in College.professor
where n.Surname == Getsurname(MyLongListSelector2.SelectedItem.ToString()) && n.FirstName == GetFirstname(MyLongListSelector2.SelectedItem.ToString())
select n.Pic == null ? defaultPic : n.Pic).Single();
Where 'defaultPic' would be a string pointing to a default or no image pic.
You could also try String.IsNullOrEmpty to check if the Pic is null or empty, but i am not sure if it would work in Linq2SQL. I know it would in EF 6.x.

Casting a nullable in where clause in LinQ-to-entity without null-check

I know I can't cast a nullable int with the value of 'null' into a non-nullable.
int? v = null;
int w = (int)v;
So I started by making my where clause with a null check. But now I see it seems to still works even without it, how is that possible?
I know I have many LogEmneIdthat is null in the database.
foreach (var logMaaler in ctx.LogMaalers.Where(lm =>
// (lm.LogEmneId != null && logEmner.Contains((short)lm.LogEmneId))
logEmner.Contains((short)lm.LogEmneId)
))
{
}
Does the LinQ-to-entity statement get rewritten as a sql query that handles the null check for me?
Does the LinQ-to-entity statement get rewritten as a sql query that handles the null check for me?
Kind of. Contains is transformed into IN clause within SQL query, which works just fine with NULL values. Consider following query:
SELECT *
FROM Table
WHERE Id IN (1,2,3,4,5,6,7)
It will work just fine when you have a row with NULL in Id column. And that's exactly what's happening here.

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.

Why does EF not return any results when comparing null variable?

I'm having an issue selecting data in my data context in Entity Framework and I've narrowed it down to querying for null values. I have a method like this:
public void DoStuff(int? someInt)
{
var someData = dataContext.MyEntities.Where(x => x.SomeProperty == someInt);
// someData always yields no results if someInt is null, even though
// there are rows in the table that have null for that column.
}
The above method fails if someInt is null. But this line works:
var someData = dataContext.MyEntities.Where(x => x.SomeProperty == null);
Why do I get data in the second one but not the first one?
I guess, then, that it is generating and using a SQL query of the form that expects a non-null value:
where x.SomeProperty = #param
Instead of the SQL to show the c# null-equality semantic:
where x.SomeProperty is null
(the key point here being that in c#, null equals null; in ANSI-SQL, null neither equals null nor (confusingly) not-equals null - different syntax is need to test nulls)
I've seen LINQ-to-SQL do the same thing, and agree that it is counter-intuitive. The only suggestion I have is: test the candidate parameter for null yourself and do the constant/literal == null test instead. It would also probably be able to do the same by inspecting and expression tree and re-writing it, if you are into expression trees - but special-casing the null is simpler.
someInt isn't null on its own. someInt.Value would be null.

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