Почему Mongo IQueryable создает исключение InvalidOperationException при применении $ filter к ExtraElements через OData? - PullRequest
0 голосов
/ 28 декабря 2018

Попытка интеграции стека Microsoft OData v4 с драйвером Mongo C #.Я хотел бы предоставить коллекцию Mongo и включить операцию фильтра OData $ для полей, содержащихся в словаре ExtraElements.

Я создал минимальный пример проблемы.Начиная с пустого проекта WebAPI в Visual Studio 2015, я создал следующую модель:

  public class TestEntity
  {
    [BsonId, BsonRepresentation(BsonType.ObjectId)]
    public string _id { get; set; }

    public string Id { get; set; }

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

Я раскрыл EDM EntitySet через OData, добавив следующее в конце метода WebApiConfig.Register():

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

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

Наконец, я создал простой 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;
    }
  }

Я добавил фактический объект в коллекцию Mongo:

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

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

Теперь я могу запрашивать поиск, если не пытаюсь использовать $ filter для ExtraElements:

http://localhost:63927/odata/test

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

Однако при попытке фильтрации по Name (одному из ExtraElements) возникает следующая ошибка:

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()

Если я добавлю свойство, такое как public string Name { get; set; }, в класс TestEntity, фильтрация будет работать, как и ожидалось, однако я ищу решение, позволяющее фильтровать элементы BsonExtraElements.

...