You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core API的OData中启用嵌套JSON结果

解决OData返回JSON不包含嵌套关联实体的问题

问题原因

OData默认不会自动序列化导航属性(即你通过EF Core Include关联的CostCenter、EquipmentCategory、equipmentType),除非在EDM模型中明确配置这些导航属性的可访问性,或者客户端通过$expand参数主动请求展开。你的当前EDM模型仅注册了Equipment实体集,未确保关联的导航属性被纳入OData模型体系。

解决方案

1. 确认实体类导航属性定义合规

首先检查Equipment类中的导航属性是否为public且包含get/set访问器,示例如下:

public class Equipment
{
    // 主键及基础属性
    public int Id { get; set; }
    // 其他业务属性...

    // 导航属性(建议统一使用PascalCase命名规范)
    public CostCenter CostCenter { get; set; }
    public EquipmentCategory EquipmentCategory { get; set; }
    public EquipmentType EquipmentType { get; set; }
}

2. 更新EDM模型,显式配置导航属性

修改GetEdmModel方法,让OData模型识别并允许展开导航属性,有两种实现方式:

方式一:依赖自动发现并全局允许展开

如果实体类的外键关联定义正确,ODataConventionModelBuilder可自动识别导航属性,只需显式开启展开权限:

static IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new();
    var equipmentSet = builder.EntitySet<Equipment>("Equipments");
    
    // 允许所有导航属性被展开,同时开启Select支持
    equipmentSet.EntityType.Expand().Select();
    
    // 也可针对单个导航属性单独配置
    // equipmentSet.EntityType.NavigationProperty(e => e.CostCenter).Expandable();
    // equipmentSet.EntityType.NavigationProperty(e => e.EquipmentCategory).Expandable();
    // equipmentSet.EntityType.NavigationProperty(e => e.EquipmentType).Expandable();
    
    return builder.GetEdmModel();
}

方式二:手动注册所有关联实体(适用于自动发现失效场景)

如果自动识别关联有问题,可手动注册所有涉及的实体集并配置导航关系:

static IEdmModel GetEdmModel()
{
    var builder = new ODataConventionModelBuilder();
    
    // 注册所有关联的实体集
    builder.EntitySet<Equipment>("Equipments");
    builder.EntitySet<CostCenter>("CostCenters");
    builder.EntitySet<EquipmentCategory>("EquipmentCategories");
    builder.EntitySet<EquipmentType>("EquipmentTypes");
    
    // 配置Equipment与其他实体的关联关系(根据实际关联类型调整Required/Optional)
    var equipmentEntity = builder.EntityType<Equipment>();
    equipmentEntity.HasRequired(e => e.CostCenter);
    equipmentEntity.HasRequired(e => e.EquipmentCategory);
    equipmentEntity.HasRequired(e => e.EquipmentType);
    
    return builder.GetEdmModel();
}

3. 客户端通过$expand参数请求展开

EDM模型配置完成后,客户端可通过URL参数指定要展开的导航属性,示例请求:

GET /odata/Equipments?$expand=CostCenter,EquipmentCategory,EquipmentType

4. 服务器端默认展开(可选)

若希望无需客户端指定参数,默认返回嵌套数据,可在控制器方法中添加[Expand]特性:

[HttpGet]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
[Expand("CostCenter,EquipmentCategory,EquipmentType")]
public ActionResult<IQueryable<Equipment>> Get()
{
    var eqList = _sqlServerContext.Equipments
        .Include(x => x.CostCenter)
        .Include(x => x.EquipmentCategory)
        .Include(x => x.EquipmentType);

    return Ok(eqList);
}

额外注意事项

  • 确保EF Core的DbContext中正确配置了实体间的关联关系(如外键映射),否则Include操作可能无法正确加载关联数据。
  • 检查导航属性命名,你的代码中equipmentType为小写开头,建议统一使用PascalCase规范,避免序列化或模型识别异常。
  • 确认Program.cs中OData中间件配置正确:
builder.Services.AddControllers().AddOData(options =>
{
    options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100);
    options.AddRouteComponents("odata", GetEdmModel());
});

内容的提问来源于stack exchange,提问作者Alex Wright

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 20:25:16