[CSHARP-1453] Expressions used to resolve field names for enum members do not work Created: 19/Oct/15  Updated: 03/Mar/17  Resolved: 03/Mar/17

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

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

Win8.1


Issue Links:
Duplicate
duplicates CSHARP-1867 Non-nullable members cannot be compar... Closed

 Description   

Given the class and enum:

class Person
{
	public Color FavoriteColor { get; set; }
}
 
enum Color
{
	Blue,
	SomethingElse
}

The following code snippet will not work:

Builders<Person>.IndexKeys.Ascending(x => x.FavoriteColor);
Builders<Person>.Filter.Eq(x => x.FavoriteColor, Color.Blue);
// other builders as well

Workaround

Use the string field name of the member. Even if you have mapped it to a different element name, as long as the member name is used, it will still get mapped:

Builders<Person>.IndexKeys.Ascending("FavoriteColor");



 Comments   
Comment by Robert Stam [ 03/Mar/17 ]

The underlying issue is comparing a non-nullable member to a nullable value (as mentioned in the Oct 19 comment).

This was fixed by CSHARP-1867.

Comment by Nick Judson [ 19/Oct/15 ]

It's definitely minor - just threw me for a loop because I know you fixed the enum expressions previously. Thanks for the tip - once the whole team is on 2015, we'll be able to use the new stuff.

Comment by Craig Wilson [ 19/Oct/15 ]

Ok, I'll see if I can get it to repro. I'll have to think about whether we need to fix this or not. Technically, you are passing a nullable enum value against something that expects just the enum. I'm wondering why the C# compiler is even allowing this, but since it does, we should try and figure out how to accommodate it. We are in the process of releasing 2.1 right now, so this would have to be a fix later on.

Just as a reminder, since you are on VS2015, you can use the nameof operator now which gives you all the benefits of the expression version without the runtime overhead. So...

query.Add(Builders<MyType>.Filter.Eq(nameof(MyType.QueueType), nullableEnum));

Comment by Nick Judson [ 19/Oct/15 ]

[BsonElement("qt")]
    [DataMember]
    public QueueType QueueType { get; set; }

Comment by Craig Wilson [ 19/Oct/15 ]

How is the QueueType property defined in the MyType class? Is it nullable or just the enum?

Comment by Nick Judson [ 19/Oct/15 ]

Ok, here is what I was doing:

// fails when passing a nullable enum (with a value) as the query argument
if(nullableEnum.HasValue)
  query.Add(Builders<MyType>.Filter.Eq(m => m.QueueType, nullableEnum));
 
// works
if(nullableEnum.HasValue)
  query.Add(Builders<MyType>.Filter.Eq("QueueType", nullableEnum));
 
// instead of passing the nullable var, pass its value -> works
if(nullableEnum.HasValue)
  query.Add(Builders<MyType>.Filter.Eq(m => m.QueueType,nullableEnum.Value));

Comment by Nick Judson [ 19/Oct/15 ]

I'll see what I can do. Stay tuned.

Comment by Craig Wilson [ 19/Oct/15 ]

That's what we are using as well. We have seen a few differences around roslyn and the previous compiler with regards to the expression trees generated which is why I asked.

I have written a number of tests around this now and am not making it fail. Also, the Nullable reference in the middle is extremely odd. Are you sure that your class definition is public Color FavoriteColor and not public Color? FavoriteColor?

Could you provide a simple repro in a Console app form? I simply can't make this fail...

Comment by Nick Judson [ 19/Oct/15 ]

This is on VS.NET 2015.

Comment by Craig Wilson [ 19/Oct/15 ]

Hi Nick...

I can't reproduce this. I could before, but the previous fix seems to have worked. What version of the build tools/Visual Studio are you using?

Craig

Comment by Nick Judson [ 19/Oct/15 ]

Apologies for the clone - this is for the 2.1.0.140 build. Switching my workaround (using string field name) back to lambda expressions, I get the following:

[Exception] Unable to cast object of type 'MongoDB.Bson.Serialization.Serializers.EnumSerializer`1[Connexion.Core.QueueType]' to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.Nullable`1[Connexion.Core.QueueType]]'. at MongoDB.Driver.ExpressionFieldDefinition`2.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.SimpleFilterDefinition`2.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.AndFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.MongoCollectionImpl`1.FindAsync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
at MongoDB.Driver.FindFluent`2.ToCursorAsync(CancellationToken cancellationToken)
at MongoDB.Driver.IAsyncCursorSourceExtensions.<ToListAsync>d__4`1.MoveNext()

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