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

SEGW中如何正确实现OData的$expand查询?

解决OData多对多关系$expand查询无输出问题

问题场景

在SEGW中为OData服务实现$expand查询选项,UsersSet与ProductsSet为多对多(m:n)关系,通过中间表UsersProducts的userid和productid字段关联。期望通过/UsersSet?$expand=ToProducts返回每个用户关联的所有产品,但网关测试无输出,调试发现er_entityset内容与SQL构建的深度结构不匹配,且read_entityset等方法也会执行。

现有实现代码

MPC_EXT类中定义深度实体类型

types: BEGIN OF TY_USERPRODUCTS ,
    INCLUDE TYPE ZCL_ZALM_FS_APP_MPC_EXT=>ts_users,
    toproducts TYPE STANDARD TABLE OF ZCL_ZALM_FS_APP_MPC_EXT=>ts_products WITH DEFAULT KEY,
    END OF TY_USERPRODUCTS.

types: TT_USERPRODUCTS TYPE STANDARD TABLE OF TY_USERPRODUCTS.

DPC_EXT类中重写GET_EXPANDED_ENTITYSET方法

method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITYSET.

    DATA : lt_deep_userProd TYPE TABLE OF zcl_zalm_fs_app_MPC_EXT=>ty_userproducts, "Deep Entity Type
           ls_deep_userProd TYPE zcl_zalm_fs_app_MPC_EXT=>ty_userproducts,         "Deep Entity Type
           ls_product        TYPE zcl_zalm_fs_app_MPC_EXT=>ts_products,
           ls_reluprod TYPE zcl_zalm_fs_app_mpc_ext=>ts_reltableusersproducts,
           lt_products TYPE TABLE OF zcl_zalm_fs_app_MPC_EXT=>ts_products.

    DATA(lv_expand) = io_tech_request_context->get_expand( ).
    DATA(lv_top) = io_tech_request_context->get_top( ).
    DATA(lv_skip) = io_tech_request_context->get_skip( ).
    DATA numTop TYPE int8.
    numTop = lv_top.
    DATA numSkip TYPE int8.
    numSkip = lv_skip.

    IF lv_top IS INITIAL.
      numTop = 10.
    ENDIF.
* Based on the entity set
    IF iv_entity_set_name = 'UsersSet'.
      SELECT * FROM zalm_fs_users
        INTO TABLE @DATA(lt_users)
        UP TO @numTop ROWS.

      IF sy-subrc = 0.
        SELECT * FROM zalm_fs_reluprod
          INTO TABLE @DATA(lt_reluprod)
          FOR ALL ENTRIES IN @lt_users
          WHERE userid = @lt_users-id.
      ENDIF.
      IF lt_users IS NOT INITIAL AND lt_reluprod IS NOT INITIAL.
        LOOP AT lt_users into DATA(ls_user).


          ls_deep_userProd-include = CORRESPONDING #( ls_user ).
          SELECT * FROM zalm_fs_reluprod
            INTO TABLE @DATA(lt_reluprod2)
            WHERE userid = @ls_user-id.

          LOOP AT lt_reluprod2 into ls_reluprod.
            SELECT SINGLE * FROM ZALM_FS_PRODUCTS
              WHERE id = @ls_reluprod-productid
              INTO @DATA(uprod).
              APPEND uprod TO ls_deep_userProd-toproducts.
         ENDLOOP.
         APPEND ls_deep_userprod TO lt_deep_userprod.
         CLEAR ls_deep_userprod-toproducts.

      ENDIF.

* For converting the data in the deep structure to the output format
      CALL METHOD me->/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref
        EXPORTING
          is_data = lt_deep_userprod
        CHANGING
          cr_data = er_entityset.

  ENDIF.
endmethod.

问题排查与解决方案

1. 严格匹配导航属性名称

OData网关对字段名称大小写敏感,代码中定义的toproducts必须与SEGW中配置的导航属性技术名称完全一致(此处为ToProducts)。修改MPC_EXT中的类型定义:

types: BEGIN OF TY_USERPRODUCTS ,
    INCLUDE TYPE ZCL_ZALM_FS_APP_MPC_EXT=>ts_users,
    ToProducts TYPE STANDARD TABLE OF ZCL_ZALM_FS_APP_MPC_EXT=>ts_products WITH DEFAULT KEY,
    END OF TY_USERPRODUCTS.

2. 重构方法逻辑,避免自定义深度实体

无需自定义深度实体类型,直接使用SEGW生成的用户实体类型,通过导航属性关联产品集合,框架会自动处理序列化。同时优化SQL性能,避免循环内查询:

method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITYSET.
    DATA: lt_users TYPE TABLE OF zcl_zalm_fs_app_mpc_ext=>ts_users,
          ls_user TYPE zcl_zalm_fs_app_mpc_ext=>ts_users,
          lt_rel TYPE TABLE OF zalm_fs_reluprod,
          lt_products TYPE TABLE OF zcl_zalm_fs_app_mpc_ext=>ts_products,
          lv_expand TYPE string.

    lv_expand = io_tech_request_context->get_expand( ).
    " 仅当expand包含ToProducts时处理
    IF iv_entity_set_name = 'UsersSet' AND lv_expand CS 'ToProducts'.
        " 获取用户数据(支持top/skip)
        SELECT * FROM zalm_fs_users
          INTO TABLE lt_users
          UP TO ( COND #( WHEN lv_top IS NOT INITIAL THEN lv_top ELSE 10 ) ) ROWS
          OFFSET ( lv_skip ).

        IF lt_users IS NOT INITIAL.
            " 批量获取关联关系
            SELECT * FROM zalm_fs_reluprod
              INTO TABLE lt_rel
              FOR ALL ENTRIES IN lt_users
              WHERE userid = lt_users-id.

            " 批量获取关联产品
            SELECT * FROM zalm_fs_products
              INTO TABLE lt_products
              FOR ALL ENTRIES IN lt_rel
              WHERE id = lt_rel-productid.

            " 关联用户与产品
            LOOP AT lt_users INTO ls_user.
                " 筛选当前用户的产品
                DATA(lt_user_products) = VALUE #( FOR rel IN lt_rel WHERE ( userid = ls_user-id )
                                                  FOR prod IN lt_products WHERE ( id = rel-productid )
                                                  NEXT prod ).
                " 给用户实体的导航属性赋值
                ls_user-ToProducts = lt_user_products.
                MODIFY lt_users FROM ls_user.
            ENDLOOP.
        ENDIF.

        " 将用户集合赋值给输出
        CALL METHOD me->/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref
          EXPORTING
            is_data = lt_users
          CHANGING
            cr_data = er_entityset.
    ELSE.
        " 无expand时调用标准read_entityset逻辑
        super->/iwbep/if_mgw_appl_srv_runtime~get_expanded_entityset(
            EXPORTING
                iv_entity_set_name = iv_entity_set_name
                iv_source_name     = iv_source_name
                io_tech_request_context = io_tech_request_context
                it_filter_select_options = it_filter_select_options
                it_order            = it_order
            CHANGING
                er_entityset       = er_entityset
                es_response_context = es_response_context
        ).
    ENDIF.
endmethod.

3. 覆盖完整场景,避免read_entityset干扰

当无$expand参数时,在GET_EXPANDED_ENTITYSET中调用父类方法,确保框架不会回退到read_entityset执行,保证逻辑一致性。

4. 检查SEGW导航属性配置

  • 确认Users实体已创建名为ToProducts的导航属性,关联到Products实体,关联类型设为多对多,并正确绑定中间表的字段映射。
  • 重新生成服务(Generate Runtime Objects),确保配置变更生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:47:13