【问题标题】:Mapstruct - Send nested entity having (one-to-many relation) in the responseMapstruct - 在响应中发送具有(一对多关系)的嵌套实体
【发布时间】:2016-12-29 09:25:58
【问题描述】:

我有 2 个实体 CallRecordsCallRecordOperators 具有一对多关系,如下所示

 public class CallRecords {

    @Id
    @Column(name = "id", unique = true)
    private String id;

    @Column(columnDefinition = "varchar(255) default ''")
    private String callerNumber = "";

    @OneToMany(mappedBy="callrecord")
    private List<CallRecordOperators> callRecordOperators = new ArrayList<CallRecordOperators>();


   //getter setters
}

public class CallRecordOperators {

    @Id
    @Column(name = "id", length = 50, unique = true, nullable = false, insertable = false, updatable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "callRecordId")
    private CallRecords callrecord;

    @ManyToOne
    @JoinColumn(name = "operatorId")
    private Operator operator;

    @Formats.DateTime(pattern = "yyyy-MM-dd HH:mm:yy")
    @Column(columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP")
    private Date startTime = new Date();

    @Column(columnDefinition = "varchar(100) default ''")
    private String dialStatus;

   //getter setter
}

因此,如果用户要求提供所有“CallRecords”数据,我还必须提供“CallRecordOperators”,因为它们是相关的。

Mapper 和 DTO 的当前代码

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface CallRecordsMapper {

    CallRecordsMapper INSTANCE = Mappers.getMapper(CallRecordsMapper.class);

    @Mapping(source="callRecordOperators",target = "operators")
    CallRecordsDto callRecordsToCallRecordsDto(CallRecords callRecords);

    public abstract CallRecordOperatorsDto toTarget(CallRecordOperators source);

    List<CallRecordsDto> callRecordsToCallRecordsDtos(List<CallRecords> callRecords);

}

public class CallRecordsDto {

    private String callerNumber;

    private List<CallRecordOperatorsDto> operators;

    //getter setters
}

public class CallRecordOperatorsDto {

    private String callRecordsId;

    private String operatorId;
    private String operatorName;

    private String currentTime;

   // getter setter

}

但是对于上面的代码,我得到了

{
    "callerNumber": "9898989898",
    "operators": [{
        "callRecordsId": null,
        "operatorId": null,
        "operatorName": null,
        "currentTime": null
    }, {
        "callRecordsId": null,
        "operatorId": null,
        "operatorName": null,
        "currentTime": null
    }]
}

运算符数组的值为空。他可能有什么问题?

【问题讨论】:

  • 您能否也分享一下您的目标类型 (DTO) 的定义? IIUC,您想将A#bs 中的一个条目的属性映射到A 的DTO 中的属性。那会是哪个B?您最好的方法可能是使用表达式来选择正确的值:@Mapping(target="property1", expression="java(bs.get(0).property1)")
  • @Gunnar 用我的实际实体更新了问题。我想要我的第一个实体中的第二个实体列表,如上所示。

标签: java hibernate one-to-many dto mapstruct


【解决方案1】:

您似乎缺少从CallRecordOperatorsCallRecordOperatorsDto 的映射:

@Mapper
public interface CallRecordsMapper {

    CallRecordsMapper INSTANCE = Mappers.getMapper(CallRecordsMapper.class);

    @Mapping(source="callRecordOperators",target = "operators")
    CallRecordsDto callRecordsToCallRecordsDto(CallRecords callRecords);

    @Mapping(target = "callRecordsId", source = "callrecord.id")
    @Mapping(target = "operatorId", source = "operator.id")
    @Mapping(target = "operatorName", source = "operator.name")
    @Mapping(target = "currentTime", source = "startTime")
    CallRecordOperatorsDto callRecordOperatorsToDto(CallRecordOperators source);
}

【讨论】:

    【解决方案2】:

    当您对A 元素进行Hibernate 查询时,您可以使用不同的策略获取bs 集合的相关B 元素。其中一些是:

    1. 如果您使用 HQL 构建查询,您可以使用 JOIN FETCHLEFT JOIN FETCH 来填充 bs 集合:

      String hql = "SELECT DISTINCT a FROM " + A.class.getName() 
          + " a LEFT JOIN FETCH a.bs WHERE ...";
      

      此查询将使用单个 SQL 查询加载所有数据。

    2. 使用 bs 集合的即时获取,更改 @OneToMany 注释:

      @OneToMany(fetch=FetchType.EAGER)
      private List<B> bs;
      

      在这种情况下,当您运行 A 元素的查询时,将启动 SQL 查询以检索 A 数据,并且对于结果中的每个 A 对象,将执行 SQL 查询以加载对应的bs集合。

    3. 如果您使用Criteria 构建查询,您可以更改bs 集合的获取模式,方法类似于HQL JOIN FETCH

      Criteria c = session.createCriteria(A.class);
      c.setFetchMode("bs", FetchMode.JOIN);
      c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
      

    【讨论】:

      【解决方案3】:

      改用稍微不同但效果更好的方法怎么样?通过使用Blaze-Persistence Entity Views,您可以直接在 DTO 类上定义您的映射,并将其应用到查询构建器上,以生成完全适合您的 DTO 结构的高效查询。

      @EntityView(CallRecords.class)
      public interface CallRecordsDto {
          // The id of the CallRecords entity
          @JsonIgnore
          @IdMapping("id") String getId();
      
          String getCallerNumber();
      
          @Mapping("callRecordOperators")
          List<CallRecordOperatorsDto> getOperators();
      }
      
      @EntityView(CallRecordOperators.class)
      public interface CallRecordOperatorsDto {
      
          // The id of the CallRecordOperators entity
          @JsonIgnore
          @IdMapping("id") Long getId();
      
          @Mapping("callrecord.id")
          String getCallRecordId();
      
          @Mapping("operator.id")
          String getOperatorId();
      
          @Mapping("operator.name")
          String getOperatorName();
      
          @Mapping("startTime")
          String getCurrentTime();
      
          // Whatever properties you want
      }
      

      了解如何在 DTO 中映射实体属性?查询代码来了

      EntityManager entityManager = // jpa entity manager
      CriteriaBuilderFactory cbf = // query builder factory from Blaze-Persistence
      EntityViewManager evm = // manager that can apply entity views to query builders
      
      CriteriaBuilder<User> builder = cbf.create(entityManager, CallRecords.class)
          .where("callerNumber").eq("123456789");
      List<CallRecordsDto> result = evm.applySetting(
          builder, 
          EntityViewSetting.create(CallRecordsDto.class)
      ).getResultList();
      

      注意,这将大致生成以下优化查询

      SELECT 
          c.id, 
          c.callerNumber, 
          o.callrecord.id, 
          o.id,
          o.startTime,
          op.id,
          op.name
      FROM CallRecords c
      LEFT JOIN c.callRecordOperators o
      LEFT JOIN o.operator op
      WHERE c.callerNumber = :param_1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-22
        • 2016-01-13
        • 2011-07-21
        • 2018-06-12
        相关资源
        最近更新 更多