Asp.net WebApi OData V4中嵌套$expands的问题

11

我有一个基于Asp.net WebApi (OWIN)的OData V4

除了尝试查询四级$expand时出现问题外,其他都很顺利。

我的查询类似于:

http://domain/entity1($expand=entity2($expand=entity3($expand=entity4)))

我没有收到任何错误信息,但是最后一个展开在我的响应中没有被显示。

更多信息:

  1. 我将MaxExpandDepth设置为10。
  2. 我所有的实体都是EntitySets
  3. 我正在使用ODataConventionModelBuilder
  4. 我已经打开了SQL Profiler,并且可以看到查询(和结果)是正确的。它是在查询执行后发生的一些过滤。
  5. 我已经在网上搜索并没有找到合适的东西。
  6. 我尝试了不同的实体级别的$expands,但它们也不能正常工作。

编辑:

我重写了OnActionExecuted

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    base.OnActionExecuted(actionExecutedContext);

    var objectContent = actionExecutedContext.Response.Content as ObjectContent;
    var val = objectContent.Value;

    var t = Type.GetType("System.Web.OData.Query.Expressions.SelectExpandWrapperConverter, System.Web.OData");
    var jc = Activator.CreateInstance(t) as JsonConverter;
    var jss = new JsonSerializerSettings();
    jss.Converters.Add(jc);

    var ser = JsonConvert.SerializeObject(val, jss);
 }

序列化值包含entity4。

我仍然不知道哪个组件在管道中删除了entity4。

编辑#2:

我已经创建了一个适配器,覆盖了DefaultODataSerializerProvider和所有其他ODataEdmTypeSerializer's。我看到在过程中$expand对于entity4存在,当调用ODataResourceSerializer.CreateNavigationLink方法时,它返回null。

我跳进源代码,看到SerializerContext.Items的项中不包括entity4,SerializerContext.NavigationSource为null。

具体版本是System.Web.OData, Version=6.1.0.10907


你如何设置MaxExpandDepth?你能展示一下控制器的代码吗? - J.Loscos
@J.Loscos - 在放置在Get方法上方的EnableQueryAttribute内部。我知道我做得正确,因为过去我曾因MaxDepth不受支持而需要将值修改为3。 - Amir Popovich
你使用的是哪个版本的Microsoft.AspNet.OData?我用了6.1.0版本进行了快速测试,一个4级展开查询没有任何问题。 - J.Loscos
@J.Loscos - 是的,我正在使用6.1.0版本。我正在使用ILSpy来解决这个问题。正如我之前所说的那样,生成的SQL返回第四级,调用EnableQueryAttribute内部的ApplyQuery方法后生成的IQueryable也是如此。 - Amir Popovich
@J.Loscos - 你能否在这里粘贴你成功的4级$expand响应中的odata.context? - Amir Popovich
显示剩余2条评论
1个回答

5

好的,我注意到问题是由于我的导航属性类型为EdmUnknownEntitySet,并且导航属性查找返回null(源代码附带一个邪恶的TODO..):

/// <summary>
/// Finds the entity set that a navigation property targets.
/// </summary>
/// <param name="property">The navigation property.</param>
/// <returns>The entity set that the navigation propertion targets, or null if no such entity set exists.</returns>
/// TODO: change null logic to using UnknownEntitySet
public override IEdmNavigationSource FindNavigationTarget(IEdmNavigationProperty property)
{
    return null;
}

所以,我明白我的问题出在EdmUnknownEntitySet上。查看了代码后发现,我需要向我的导航属性中添加ContainedAttribute。由于我的解决方案有点类似于通用存储库,所以我已经在所有导航属性的启动项中添加了它。
builder.OnModelCreating = mb => mb.StructuralTypes.SelectMany(s => s.NavigationProperties
            .Where(np => np.Multiplicity == EdmMultiplicity.Many)).Distinct().ForEach(np => np.Contained());

//......

var model = builder.GetEdmModel();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接