$选择和$扩大突破ODataQueryOptions - 如何解决? [英] $select and $expand break ODataQueryOptions -- how to fix?

查看:913
本文介绍了$选择和$扩大突破ODataQueryOptions - 如何解决?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用的是Microsoft ASP.NET MVC的OData的WebAPI我们的Web服务。由于周围的层次ID(这是这次谈话的范围之内)的一些数据结构的问题,我们的一些GET操作必须使用ODataQueryOptions和手动操作前pression增加额外的限制。我们这样做是这样的(错误处理code去掉,并呼吁联为清楚起见其他方法):

We are using Microsoft ASP.NET MVC OData WebAPI for our web services. Because of some data architecture issues surrounding hierarchy ID (which are outside the scope of this conversation), some of our GET operations have to use ODataQueryOptions and manually manipulate the expression to add additional restrictions. We do so like this (error handling code removed and calls to other methods inlined for clarity):

public IQueryable<Person> Get(ODataQueryOptions<Person> oDataQueryOptions)
{
    IQueryable<Person> result;
    IQueryable<Person> dataSet = context.Persons;

    var tempQuery = oDataQueryOptions.ApplyTo(dataSet).Cast<Person>();
    var modifier = new HierarchyNodeExpressionVisitor(GetDescendantsOfNode, GetAncestorsOfNode);
    var expression = modifier.ModifyHierarchyNodeExpression(tempQuery.Expression);

    result = context.Persons.Provider.CreateQuery<Person>(expression);

    return result;
}

这已经有一段时间了伟大的工作,但我们一直在热切等待选择和展开,使我们可以更好地控制我们从我们的服务中得到的数据。星期一,我们我们的开发环境更新的WebAPI的OData 5.0.0-RC1,并获得选择和展开工作,但我们不能用它对付这些服务的使用ODataQueryOptions。我们只能用它对付我们的其他服务。如果我们查询code以上使用 $选择和/或 $展开,我们得到以下错误:

This has worked great for some time, but we've been eagerly awaiting select-and-expand so that we can better control the data we receive from our services. Monday we updated our dev environment to WebApi OData 5.0.0-rc1 and got select-and-expand working, but we can't use it against these services that use ODataQueryOptions. We can only use it against our other services. If we query the code above using $select and/or $expand, we get the following error:

"message": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
"type": "System.InvalidOperationException",
"stacktrace": "",
"internalexception":
{
    "message": "Unable to cast the type 'System.Web.Http.OData.Query.Expressions.SelectAllAndExpand`1' to type 'OurCompany.Domains.Data.Models.Person'. LINQ to Entities only supports casting EDM primitive or enumeration types.",
    "type": "System.NotSupportedException",
    "stacktrace": " at System.Data.Objects.ELinq.ExpressionConverter.ValidateAndAdjustCastTypes(TypeUsage toType, TypeUsage fromType, Type toClrType, Type fromClrType) at System.Data.Objects.ELinq.ExpressionConverter.GetCastTargetType(TypeUsage fromType, Type toClrType, Type fromClrType, Boolean preserveCastForDateTime) at System.Data.Objects.ELinq.ExpressionConverter.CreateCastExpression(DbExpression source, Type toClrType, Type fromClrType) at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.CastMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call) at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq) at System.Data.Objects.ELinq.ExpressionConverter.Convert() at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.IEnumerable.GetEnumerator() at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext) at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders) at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.WebHost.HttpControllerHandler.d__10.MoveNext()"
}

我做了一些谷歌搜索和偶然<一个href=\"https://aspnetwebstack.$c$cplex.com/wikipage?title=%24select%20and%20%24expand%20support&referringTitle=Specs\">this和<一个href=\"http://stackoverflow.com/questions/18569779/implementing-select-with-webapi-and-odataqueryoptions\">this,但也不是有帮助的。没人似乎做得就是我们正在做的,并试图使用select和扩张。我们如何解决这个问题?我不知所措我在这里...

I've done some Googling and stumbled upon this and this, but neither were helpful. Nobody appears to be doing quite what we're doing and trying to use select-and-expand. How do we fix this? I'm at a loss here...

推荐答案

现在的问题是在这条线code的,

The problem is in this line of code,

var tempQuery = oDataQueryOptions.ApplyTo(dataSet).Cast<Person>();

的演员,因为一旦 $选择 $展开应用的结果是不再是一个人是无效的。这将是一个包装&LT;&人GT; 仅包含客户端请求的属性。您可能需要修改 HierarchyNodeEx pressionVisitor 考虑到这一点。

The Cast is invalid as once $select and $expand are applied the result is no longer a Person. It would be a Wrapper<Person> that contains only the properties that the client asked for. You might have to modify your HierarchyNodeExpressionVisitor to take this into consideration.

此外,尝试改变你的行动在处理事实结果可能不是的IQueryable&LT;人方式&gt;

Also, try changing your action to this to handle the fact that the result might not be a IQueryable<Person> anymore.

    public IHttpActionResult Get(ODataQueryOptions<Person> oDataQueryOptions)
    {
        IQueryable result;
        IQueryable<Person> dataSet = context.Persons;

        IQueryable tempQuery = oDataQueryOptions.ApplyTo(dataSet);
        var modifier = new HierarchyNodeExpressionVisitor(GetDescendantsOfNode, GetAncestorsOfNode);
        var expression = modifier.ModifyHierarchyNodeExpression(tempQuery.Expression);

        result = context.Persons.Provider.CreateQuery(expression);

        return Ok(result, result.GetType());
    }

    private IHttpActionResult Ok(object content, Type type)
    {
        Type resultType = typeof(OkNegotiatedContentResult<>).MakeGenericType(type);
        return Activator.CreateInstance(resultType, content, this) as IHttpActionResult;
    }

这篇关于$选择和$扩大突破ODataQueryOptions - 如何解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆