尝试将Microsoft OData v4堆栈与Mongo C#驱动程序集成。我想公开一个Mongo集合并针对ExtraElements词典中包含的字段启用OData $ filter操作。
我创建了一个最小的问题示例。从Visual Studio 2015中的空WebAPI项目开始,我创建了以下模型:
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; }
}
我通过在WebApiConfig.Register()
方法末尾添加以下内容,通过OData公开了EDM EntitySet:
// 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”}
现在,只要不尝试在ExtraElements上使用$ filter,我就可以查询find:
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进行过滤的解决方案。