[CSHARP-1273] Find() fails with "Object reference not set to an instance of an object." Created: 11/May/15  Updated: 22/Dec/16  Resolved: 22/Dec/16

Status: Closed
Project: C# Driver
Component/s: API
Affects Version/s: 2.0
Fix Version/s: 2.4.1

Type: Bug Priority: Minor - P4
Reporter: Sergey Ivasenko Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

VS2013, Windows 7


Attachments: Text File StackTrace.txt    
Issue Links:
Related
is related to CSHARP-1867 Non-nullable members cannot be compar... Closed

 Description   

The following code fails with NullReference exception:

int? key = null;
collection.Find(r => r.RequestId == requestId && (key == null || r.Key == key)).Limit(1).FirstOrDefaultAsync();
 
// Class, stored in collection
public class Request
{
   public string RequestId {get; set;}
   public int Key {get; set;}
}

Stack trace attached.

Apparently, the problem is that the serializer selected based on the document property type, which is INT, rather than on the actual value type, which is INT?. Therefore, it later fails on NULL value, hence serializer expects ValueType, rather than reference type.



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

After the work on CSHARP-1867 this query now works, although we make no attempt to optimize it client side.

The resulting query looks like this:

"find({ \"RequestId\" : \"123\", \"$or\" : [{ }, { \"Key\" : null }] })"

Notice that the first clause of the $or matches all documents so the second clause is redundant, which in turn makes the whole $or clause redundant. That's the optimization that is not being done client side. It is likely that the server will optimize this query though.

Comment by Sergey Ivasenko [ 11/May/15 ]

Hi Craig,

This is exactly what is needed and we use now that workaround.

I understand, that this might be not that straightforward to fix it. May be, constantexpression (i.e. value expression) type should be taken to find out, which serializer to be used, hence eventually the value is serialized. But I'm not really deep into the driver code...

Sergey

Comment by Craig Wilson [ 11/May/15 ]

So, we can certainly throw a better exception.

However, this query isn't possible to render. The (key == null) is a local comparison. It sounds like what you want is this: If key == null, don't include they Key comparison. Otherwise, do... This is a check that should be done in your application...

int? key = null;
IFindFluent<TRequest> find;
if(key == null)
{
    find = collection.Find(r => r.RequestId == requestId);
}
else
{
    find = collection.Find(r => r.RequestId == requestId && r.Key == key.Value);
}
 
var result = find.FirstOrDefaultAsync(); // will add the limit 1 for you because you only asked for one.

We might be able to fix this. I haven't tried, so I'm not sure exactly what would be required. However, I'm not sure that we should as not all might agree on the outcome of this.

Craig

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