Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapstruct - Send nested entity having (one-to-many relation) in the response

Tags:

I have 2 entities CallRecords and CallRecordOperators with one-to-many relation as given below

 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
}

So if the user ask for all "CallRecords" data I also have to give "CallRecordOperators" as they are related.

Current code for Mapper and DTOs

@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

}

But for above code I am getting

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

the values of operator array are null. what could be he issue?

like image 241
singhakash Avatar asked Dec 29 '16 09:12

singhakash


2 Answers

It seems your are lacking the mappings from CallRecordOperators to CallRecordOperatorsDto:

@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);
}
like image 196
Gunnar Avatar answered Sep 25 '22 10:09

Gunnar


When you do a Hibernate query of A elements, you can fetch the related B elements of the bs collection using different strategies. Some of them are:

  1. If you use HQL to construct your queries, you can do a JOIN FETCH or LEFT JOIN FETCH to populate the bs collection:

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

    This query will load all data using a single SQL query.

  2. Use eager fetching of the bs collection, changing the @OneToMany annotation:

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

    In this case, when you run a query of A elements, a SQL query will be launched to retrieve the A data, and for each A object in the result, a SQL query will be executed to load the corresponding bs collection.

  3. If you use Criteria to build the query, you can change the fetch mode of the bs collection in a way similar to the HQL JOIN FETCH:

    Criteria c = session.createCriteria(A.class);
    c.setFetchMode("bs", FetchMode.JOIN);
    c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    
like image 22
JMSilla Avatar answered Sep 23 '22 10:09

JMSilla