[CSHARP-506] Throw better exception when comparing a non-nullable field to a nullable value Created: 20/Jun/12  Updated: 14/Dec/16  Resolved: 11/Oct/16

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.4.2, 1.5
Fix Version/s: 2.4

Type: Bug Priority: Major - P3
Reporter: Zaid Masud Assignee: Robert Stam
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by CSHARP-474 Review all exceptions thrown by the C... Closed
Related
related to CSHARP-1867 Non-nullable members cannot be compar... Closed

 Description   

Consider the following code:

int? nullableFive = 5;
var greaterThanFive = collection.AsQueryable().Where(d => d.IntField > nullableFive) // where IntField is of type int (non-nullable)

In standard LINQ implementations a comparison between a nullable and non-nullable field is valid if the nullable field has a value. If the nullable field does not have a value, the comparison will return false.

Workaround:
var greaterThanFive = collection.AsQueryable().Where(d => d.IntField > nullableFive.Value)

System..InvalidOperationException: The operands for operator 'Equal' do not match the parameters of method 'op_Equality'. at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull) at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method) at System.Linq.Expressions.Expression.MakeBinary(ExpressionType binaryType, Expression left, Expression right, Boolean liftToNull, MethodInfo method, LambdaExpression conversion) at MongoDB.Driver.Linq.ExpressionVisitor.VisitBinary(BinaryExpression node) at MongoDB.Driver.Linq.ExpressionNormalizer.VisitBinary(BinaryExpression node) at MongoDB.Driver.Linq.ExpressionVisitor.Visit(Expression node) at MongoDB.Driver.Linq.ExpressionVisitor.VisitLambda(LambdaExpression node) at MongoDB.Driver.Linq.ExpressionVisitor.Visit(Expression node) at MongoDB.Driver.Linq.ExpressionVisitor.VisitUnary(UnaryExpression node) at MongoDB.Driver.Linq.ExpressionVisitor.Visit(Expression node) at MongoDB.Driver.Linq.ExpressionVisitor.Visit(ReadOnlyCollection1 nodes) at MongoDB.Driver.Linq.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at MongoDB.Driver.Linq.ExpressionVisitor.Visit(Expression node) at MongoDB.Driver.Linq.MongoQueryTranslator.Translate(MongoQueryProvider provider, Expression expression) at MongoDB.Driver.Linq.MongoQueryProvider.Execute[TResult](Expression expression)



 Comments   
Comment by Robert Stam [ 14/Dec/16 ]

See CSHARP-1867.

We are reversing the decision that these queries are invalid and will translate them into the closest logical equivalent, even when the value is null (but note that there shouldn't be any nulls in the database if all documents were created using a POCO with a non-nullable member).

Comment by Githook User [ 11/Oct/16 ]

Author:

{u'username': u'rstam', u'name': u'rstam', u'email': u'robert@robertstam.org'}

Message: CSHARP-506: Better error message when comparing a non-nullable field to a nullable value.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/ee797128a1a3a78bb7b492b78f93d2d85b96f738

Comment by Robert Stam [ 11/Oct/16 ]

This ticket was originally opened against the 1.x driver, but it is being resolved in the new LINQ implementation in the 2.x driver.

The issue arises when you have a document like the following:

public class C
{
    public int Id;
    public int X;
}

And you write a LINQ query like this:

var nullableValue = (int?)1;
collection.AsQueryable<C>().Where(c => c.X == nullableValue);

where c.X is not nullable but nullabvleValue is.

The correct way to write this query is:

var nullableValue = (int?)1;
collection.AsQueryable().Where(c => c.X == nullableValue.Value); // use .Value to make the right side non-nullable also

Unfortunately this can't be a compile time error because of the automatic conversions defined by C#, so it is a runtime error.

Comment by Craig Wilson [ 12/Jul/12 ]

After 2 different devs spiked this separately, we can't agree on the correct behavior. This is due to the fact that a non-nullable local field can still be null in the database, and despite the msdn language, it simply doesn't account for this principle. Therefore, we are going to improve the error message in this ticket and require the use of .Value on the local nullable type.

Comment by Zaid Masud [ 20/Jun/12 ]

See official MSDN comment in this issue: http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

"When you perform comparisons with nullable types, if the value of one of the nullable types is null and the other is not, all comparisons evaluate to false except for != (not equal)"

Also please note that in my code example I used a greater than operator, but the exception was generated for an equality operator.

Generated at Wed Feb 07 21:37:02 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.