Null coalesce not working in LINQ query - c#

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.

Related

PostgreSQL, Linq C# error 'could not determine data type of parameter $1'

I am getting this error "could not determine data type of parameter $1"
and my where clause where I am getting the error is like the following:
var result = from Table in model.Table
where (filter.XId.HasValue ? Table.XId == filter.XId: true)
select new TableEntity
{
ID = Table.XId
};
If my code was only like this 'Table.X == filter.X', it works ...
How can I fix this?
and I am getting this problem only with PostgreSQL database ....
First about what that error usually means. When making parametrized queries to PostgreSQL, all parameters should be referenced in query itself. When you add more parameters than used in query, usually the error above appears.
It seems that when whatever EF provider for PosgreSQL you use converted your statement to SQL, it created more parameters than needed.
In general, it might be hard for EF providers to analyze and correctly parse statements like you used, so good practice is to use statements that are "closer" to SQL in certain sense. In your case equivalent query which is "closer" to SQL would be:
where (filter.XId == null || Table.XId == filter.XId)
If you want to generate different queries based on the value of filter, you can do something like this:
var query = (IQueryable<Table>) model.Table;
if (filter.XId != null) {
query = query.Where(row => row.XId == filter.XId);
}
var result = query.Select(row => new TableEntity {
Id = row.XId
});
As it is the first SO answer in Google -
Marked answer didn't help me in similar case (EF6 + Postgre), so I had to use .AsEnumerable();
Yeah, it could be bad for perfomance but it fitted well in my case.
So this one would work:
var query = model.Table
.AsEnumerable()
.Where (p => filter.XId.HasValue ? p.XId == filter.XId: true);

Best way to determined null or count 0

I have a iQueryable and I need to know if it's null or has no values.
IQueryable<people> L = (from p in people
where p.lastname.Contains("y")
select p);
if (L != null && L.Count() > 0) {
return "Something";
} else {
return "NOTHING";
}
Well if you use the L.Count() it will use more resources. Is there a better way? Something that does not use L.Count()
It's recommended that you use .Any().
IQueryable<people> L = (from p in people
where p.lastname.Contains("y")
select p);
if (L.Any()) {
return "Something";
} else {
return "NOTHING";
}
Does L need to be IQueryable<> ?
By using SingleOrDefault() it will be a single people (Person?) or null (presuming people is a class)
var result = (from p in people
where p.lastname.Contains("y")
select p).SingleOrDefault();
return result == null
? "NOTHING"
: "Something";
Other: Is SingleOrDefault() what you want to use or do you mean FirstOrDefault() or do you mean Any()?
Maybe LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria can help.
hth,
Alan.
An example of using the .Any method
return people.Any(p => p.lastname.Contains("y")) ? "something" : "nothing";
This is an example that would return an IQueryable if the .Any returns true, however it might be too ineffecient since it requires two round trips to the database. I'm sure a better method could be written, given enough time and thought.
return sis.Students.Any(p => p.LastName.Contains("y")) ?
people.Where(p => p.lastname.Contains("y")) : "nothing";
L.Any(), L.FirstOrDefault() will pretty much both have the same performance as they have almost identical implementation and are probably what you are looking for. Your SingleOrDefault is probably unintentional as it will throw an exception if there is more than one result.
Performance of LINQ Any vs FirstOrDefault != null
It's worth saying some of this depends on your provider. IQueryable just implies an intention. If It's Linq2Sql or something then yes L.Count() will request more resources - except that your also calling SingleOrDefault in the above line which means your null check is all you need, but your types don't match...
If I am running this statement against a Linq provider I write myself (or Amazons, or any other given LINQ provider) .Count() might be faster depending on what the provider is doing, but your assumptions hold if you're using the usual Microsoft Linq to SQL implementations.

get the names starts with numbers or special characters in linq to sql

I need to get the list of names that starts with special characters or numbers in the linq to sql query for my asp.net mvc(C#) application.
I have tried like this (Which may not be efficient):
public List<User> GetUsersStartingWithNonCharacter()
{
List<User> _dbUsers = this.GetAllUsers();
return _dbUsers.Where(p => ((p.FirstName != null && p.FirstName != string.Empty && !char.IsLetter(p.FirstName.ToLower()[0])) || (p.FirstName == null || p.FirstName == string.Empty))).ToList();
}
public List<Users> GetAllUsers()
{
return (from u in _context.pu_Users
where !u.Is_Deleted
select new User
{
UserId = u.User_Id,
Email = u.Email_Address,
FirstName = u.First_Name,
LastName = u.Last_Name
}).ToList();
}
Can anyone suggest the most efficient way to do this in linq to sql?
How do you know if it isn't already efficient? Use somekind of profiler tool, like SQL Server Profiler if you're using MSSQL, that way you can trace your call against the database and see the actual SQL. Of course you can only debug the code to see the generated SQL but it's easier with a profiler tool and you'll see how long time the query takes.
EDIT: I see one part in how you can make it more efficient:
public List<User> GetUsersStartingWithNonCharacter()
{
List<User> _dbUsers = this.GetAllUsers();
return _dbUsers.Where(p => ((p.FirstName != null && p.FirstName != string.Empty && !char.IsLetter(p.FirstName.ToLower()[0])) || (p.FirstName == null || p.FirstName == string.Empty))).ToList();
}
public IQueryable<Users> GetAllUsers()
{
return from u in _context.pu_Users
where !u.Is_Deleted
select new User
{
UserId = u.User_Id,
Email = u.Email_Address,
FirstName = u.First_Name,
LastName = u.Last_Name
};
}
Changing your GetAllUsersto return IQueryable will delay the query to execute until you've applied your filters. This might affect some other aspects of your design but you should consider it since that change might make your where clause run in the database instead of in the code which will result in less data traffic between your application and database. Again, use a profiler to see the difference :).
I'll use Regular Expression in this scenerio
Here is my sample code
return _dbUsers.Where(p=>p.FirstName!=String.Empty)
. Where(p => Regex.Match(p.Firstname[0].ToString(), "[a-zA-Z]").Success).ToList();
I suspect all rows will be retrieved and filted in your application due to the condition:
char.IsLetter(p.FirstName.ToLower()[0])
(Using a regular expression like suggested in another answer will also pull in all rows, and filter them on the client.)
It is possible to check characters in a string with the PATINDEX function, but it's seems only to be available for LINQ via the Entity framework.
You could write a stored procedure using PATINDEX directly to check for the first character to optimize your query. Sample queries can be found at http://www.databasejournal.com/features/mssql/article.php/3071531/Using-SQL-Servers-CHARINDEX-and-PATINDEX.htm.
Sometimes LINQ to whatever will not yield the most optimized solution, but that's just life. In most cases it will give clearer code, but special cases might require work arounds in order to use special operators of the underlying system.

linq where clause and count result in null exception

The code below works unless p.School.SchoolName turns out to be null, in which case it results in a NullReferenceException.
if (ExistingUsers.Where(p => p.StudentID == item.StaffID &&
p.School.SchoolName == item.SchoolID).Count() > 0)
{
// Do stuff.
}
ExistingUsers is a list of users:
public List<User> ExistingUsers;
Here is the relevant portion of the stacktrace:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Linq.Enumerable.WhereListIterator1.MoveNext()
at System.Linq.Enumerable.Count[TSource](IEnumerable1 source)
How should I handle this where clause?
Thanks very much in advance.
I suspect p.School is null, not SchoolName. Simply add a null check before accessing SchoolName. Also, use Any() to check if there are any results instead of Count() > 0 unless you're really in need of the count. This performs better since not all items are iterated if any exist.
var result = ExistingUsers.Where(p => p.StudentID == item.StaffID
&& p.School != null
&& p.School.SchoolName == item.SchoolID)
.Any();
if (result) { /* do something */ }
For all database nullable columns, we should either add null check or do simple comparision a == b instead of a.ToLower() == b.ToLower() or similar string operations.
My observation as below:
As they get iterated through Enumerable of LINQ Query for comparision against with input string/value, any null value (of database column) and operations on it would raise exception, but Enumerable becomes NULL, though query is not null.
In the case where you want to get the null value (all the student, with school or not) Use left join.
There are a good example on MSDN
If I remember correctly (not at my developer PC at the moment and can't check with Reflector), using the == operator results in calling the instance implementation string.Equals(string), not the static implementation String.Equals(string, string).
Assuming that your problem is due to SchoolName being null, as you suggest, try this:
if (ExistingUsers.Where(
p => p.StudentID == item.StaffID
&& String.Equals( p.School.SchoolName, item.SchoolID)).Count() > 0)
{
// Do stuff.
}
Of course, comments by other answers count as well:
Using Any() instead of Count() > 0 will generally perform better
If p.School is the null, you'll need an extra check
Hope this helps.

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