Reputation: 5748
The title may be ambiguous, but let me explain.
I am working with MongoDb and with the c# driver for MongoDb, we can create a FilterDefinition<T>
to create a filter to fetch data as follows :
var Filter = Builders<TestClass>.Filter.Eq(x => x.AnyProperty, Value);
I am trying to put this code inside a reusable generic method, so that i don't end up writing the same code again and again. I won't be including the entire function here, but inside the function, i am trying to do something as follows :
var Filter = Builders<T>.FIlter.Eq(x => x.AnyProperty, value);
Now the drawbacks are :
T
is a generic type, meaning it doesn't have the property i am looking for. So, i try to get the type of T
and get the property that i am looking for by name, as follows :
...FIlter.Eq(x => x.GetType().GetProperty(PropertyName), value)
This results in an exception :
Unable to determine the serialization information for x => x.GetType().GetProperty("UserName"). // UserName is the property name
So, my question is, what can i do here for the generic type, which would be equivalent of x => x.PropertyName
inside the lambda expression ?
Update
Forgot to mention, i did try this :
var Filter = Builders<T>.FIlter.Eq("PropertName", value);
But it doesn't return the results from the database, where as this does :
var Filter = Builders<MyClass>.FIlter.Eq("PropertName", value);
I really wonder why!
Update 2
Definition of Filter.Eq
is as follows :
public FilterDefinition<TDocument> Eq<TField>(FieldDefinition<TDocument, TField> field, TField value);
Upvotes: 2
Views: 1397
Reputation: 11478
In the code
FIlter.Eq(x => x.GetType().GetProperty(PropertyName), value)
, my undersatnding is that Mongo driver is expecting an Expression
, which is automatically created when you use the Metadata like in original case x => x.AnyProperty
In this case you need to explicitly supply
MemberExpression
as follows
var parameterExpression = Expression.Parameter(typeof(T),"x");
var memberAccessExpression = Expression.MakeMemberAccess(parameterExpression, typeof(T).GetProperty("AnyProperty"));
Now you can supply to the FIlter.Eq
value memberAccessExpression
, in this case it will fail at run-time, if the AnyProperty
is not part of type T
, since its verified at the run-time.
In ExpressionTrees
, this is the replacement of the x => x.AnyProperty
Edit 1:
Reviewing the Mongo DB Driver documents, following are the important details on the Definitions and Builders, there's an example as follows:
var builder = Builders<Widget>.Filter;
var filter = builder.Eq(widget => widget.X, 10) & builder.Lt(widget => widget.Y, 20);
Following is the definition of the FilterDefinitionBuilder.Eq, which expose the Eq
and various other filters:
public FilterDefinition<TDocument> Eq<TField>(Expression<Func<TDocument, TField>> field,TField value)
In this case, we need a generic type TDocument
, which is the main class and TField
, which is the type of the field on which filter is applied, therefore code in your case would be:
var builder = Builders<T>.Filter;
// Use makeMemberAccessExpression created above
var filter = builder.Eq(Expression.Lambda<Func<T,string>>(makeMemberAccessExpression), "<stringValue>");
Important points:
TDocument
and TField
, here you are working with just one, so with the above code it will be restricted to string as type for TField
, until and unless you make that also generic, which is your choice, otherwise all your fields shall be of specific type that you supply, which is string in this caseTField
that you supply else it will not work and will fail at compile timeEq<TField>(FieldDefinition<TDocument, TField>, TField)
, which would work in a similar way, but since it expects FieldDefinition<TDocument, TField>
, we need to supply the Expression<Func<TDocument,TField>>
as part of the class, both overloads translates into similar codeUpvotes: 3