craiggwilson / fluent-mongo

Provides a fluent interface on top of the 10gen driver including Linq.
172 stars 28 forks source link

Problem with IQueryable<BsonDocument> #52

Closed object closed 12 years ago

object commented 12 years ago

Hello,

This is an unusual scenario that does not happen under normal use of Fluent-Mongo. I am writing a MongoDB adapter for OData and consider your LINQ provider because I need an IQueryable interface to MongoDB collections. But I need an IQueryable, not an IQueryable.

The problem with IQueryable is that although it is supported, in your tests you are using internal class BsonDocumentQuery to build expressions. If I don't use BsonDocumentQuery and use notation Where(x => x.GetValue("key")), then Mongo query provider raises "Not supported" exception its expression visitor.

So I am stuck for the moment and would like to find a decent solution. The easiest would be to make BsonDocumentQuery public, this will open for use of its Key extension method. An alternative is to change the visitor so it accepts GetValue. Otherwise it looks like the driver does not support IQueryable, only custom types.

Please let me know what you think about it. If you want, I can investigate it more and submit a pull request.

object commented 12 years ago

Here is a test that fails with NotSupportedException:

    [Test]
    public void GetValue()
    {
        var q = BsonDocumentCollection.AsQueryable().Where(x => x.GetValue("age") > 21);
        var people = q.GetEnumerator();
    }

And the fix is to extend VisitMethodCall(MethodCallExpression m)

from:

... else if (m.Method.DeclaringType == typeof(MongoQueryable)) { if (m.Method.Name == "Key") { _fieldParts.Push((string)((ConstantExpression)m.Arguments[1]).Value); Visit(m.Arguments[0]); return m; } } ...

to

... else if (m.Method.DeclaringType == typeof(BsonDocument)) { if (m.Method.Name == "GetValue") { _fieldParts.Push((string)((ConstantExpression)m.Arguments[0]).Value); Visit(m.Object); return m; } } else if (m.Method.DeclaringType == typeof(MongoQueryable)) { if (m.Method.Name == "Key") { _fieldParts.Push((string)((ConstantExpression)m.Arguments[1]).Value); Visit(m.Arguments[0]); return m; } } ...

object commented 12 years ago

Oops, looks like this is not needed. I could simply use indexer since get_Item is supported. I am closing the issue.