|
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...
|