-
Type:
Improvement
-
Resolution: Works as Designed
-
Priority:
Major - P3
-
None
-
Affects Version/s: 2.10.0
-
Component/s: LINQ
-
None
-
None
-
None
-
None
-
None
-
None
-
None
-
None
We're using the [Microsoft Expression|https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries] to query the mongoDb dynamically using the C# Driver.
So far this was working out pretty well, but in the following scenario we're running into trouble:
// C# Model public class Item{ public Name { get; set; } public Dictionary<string, Property> Properties { get; set; } ... } public class Property { public dynamic Value { get; set; } ... }
Our configuration translates this into the following JSON in the Database (using the fluent class mapping)
// JSON in MongoDB { "Name": "Door", "Properties": { "Color": { "Value": "Red", ... }, "Height": { "Value": 300, ... }, ... }, ... }
We can query it in MongoDB shell easily as:
// Mongo shell db.getCollection('test_collection').find({'Properties.Color.Value': 'Red'})
And even in c# we can query it in link as:
// C# Linq query test_collection .AsQueryable() .Where(x => x.Properties["Color"].Value as string == "Red") .SingleOrDefault();
So far so good, this is all working nice and properly, but now comes the tricky part. The dynamic expression:
// Don't you mind this big lumb of code, but might be usefull for other readers, cause it took us a while to craft this: var parameterExpression = Expression.Parameter(typeof(T), "x"); var properties = Expression.Property(parameterExpression, "Properties"); var propertyInfo = typeof(Dictionary<string,EntityProperty>).GetProperty("Item"); var arguments = new List<Expression> { Expression.Constant("Color") }; var indexer = Expression.MakeIndex(properties, propertyInfo, arguments); var valueProperty = Expression.Property(indexer, "Value"); var compareValue = Expression.Constant("Red"); var converted = Expression.Convert(valueProperty, typeof(string)); var expression = Expression.MakeBinary(ExpressionType.Equal, converted, compareValue); var lambda = Expression.Lambda<Func<T, bool>>(expression, parameterExpression); // What this basicially does, it generates a lambda expression dynamically, // however the format is the following: // x => x.Properties.Item["Color"].Value == "Red"
If we pass this query to a local List<Item> the objects are filtered perfectly,
however when we pass this to mongodb, it gives me an error on {document}{Properties}.Item
test_collection //IMongoCollection<Item>
.AsQueryable()
.Where(lambda)
.SingleOrDefault();
Question: Should MongoDB c# driver support dynamically created Expressions for Dictionaries?
------------------------------------------
Notes:
- Dynamic expresions are working fine without Dictionaries (i.e. we filter on Name)
- The .Item is the only Way to build dynamic expressions on a dictionary
- Not sure if this is a feature request, or a bug...