Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-2466

InvalidOperationException with IQueryable and ExtraElements

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 2.7.2
    • Component/s: BSON, Linq
    • Labels:
      None

      Trying to integrate Microsoft OData v4 stack with Mongo C# Driver. I would like to expose a Mongo collection and enable the OData $filter operation against the fields contained in the ExtraElements dictionary.

      I have created a minimal example of the issue. Beginning with an empty WebAPI project in Visual Studio 2015, I created the following model:

      public class TestEntity

      { [BsonId, BsonElement("_id")] public ObjectId _id \{ get; set; }

      public string Id { get; set; }

      [BsonExtraElements]
      public Dictionary<string, object> ExtraElements { get; set; }
      }

      I exposed EDM EntitySet via OData by adding the following at the end of `WebApiConfig.Register()` method:

      // OData
      var edmBuilder = new ODataConventionModelBuilder();
      edmBuilder.EntitySet<TestEntity>("test");

      config.MapODataServiceRoute("odata", "odata", edmBuilder.GetEdmModel());

      Finally, I created a simple TestController:

      public class TestController : ODataController
      {
      [EnableQuery(AllowedFunctions = Microsoft.AspNet.OData.Query.AllowedFunctions.All)]
      public IQueryable<TestEntity> Get()

      { var mongo = new MongoClient(); var db = mongo.GetDatabase("test"); var collection = db.GetCollection<TestEntity>("test"); var result = collection.AsQueryable() as IQueryable<TestEntity>; return result; }

      }

      I added an actual object to the Mongo collection:

      > db.test.insert( {Id:'test', Name:'testName'}) WriteResult({ "nInserted" : 1 })
      > db.test.find()

      > { "_id" : ObjectId("5c266040fd7e5a3c63b33cd8"), "Id" : "test", "Name" : "testName" }

      Now I can query find as long as I don't try to use $filter on the ExtraElements (note that OData is not rendering the ObjectId field properly, but I do not believe this is related to the problem):

      http://localhost:63927/odata/test

      {"@odata.context":"http://localhost:63927/odata/$metadata#test","value":[\{"Id":"test","Name":"testName","_id":{}}]}

      However, if I try to filter against the `Name` (one of the `ExtraElements`) the following error occurs:

      http://localhost:63927/odata/test?$filter=Name%20eq%20%27testName%27

      *Message: Convert(IIF((({document}

      {ExtraElements} != null) AndAlso {document}{ExtraElements}

      .ContainsKey(\"Name\")), {document}

      {ExtraElements}

      .Item[\"Name\"], null)) is not supported.*

      Exception: System.InvalidOperationException

      Stack Trace:
      at MongoDB.Driver.Linq.Translators.PredicateTranslator.GetFieldExpression(Expression expression)
      at MongoDB.Driver.Linq.Translators.PredicateTranslator.TranslateComparison(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
      at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node)
      at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
      at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslateWhere(WhereExpression node)
      at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslatePipeline(PipelineExpression node)
      at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
      at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Execute(Expression expression)
      at MongoDB.Driver.Linq.MongoQueryableImpl`2.GetEnumerator()
      at Microsoft.AspNet.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext)
      at Microsoft.AspNet.OData.Formatter.ODataOutputFormatterHelper.WriteToStream(Type type, Object value, IEdmModel model, ODataVersion version, Uri baseAddress, MediaTypeHeaderValue contentType, IWebApiUrlHelper internaUrlHelper, IWebApiRequestMessage internalRequest, IWebApiHeaders internalRequestHeaders, Func`2 getODataMessageWrapper, Func`2 getEdmTypeSerializer, Func`2 getODataPayloadSerializer, Func`1 getODataSerializerContext)
      at Microsoft.AspNet.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
      — End of stack trace from previous location where exception was thrown —
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
      at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()

       

            Assignee:
            wan.bachtiar@mongodb.com Wan Bachtiar
            Reporter:
            vugenti Vincent Ugenti
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: