5

I have a question about @ManyToOne mapping in the mapstruct. I have two tables

The first one:

@Entity
@Table(name = "members", schema = vsm)
public class MemberEntity{

    @Column(name = "id", nullable = false)
    protected Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "case_id", nullable = false)
    private CaseEntity case;
}

And the second one:

@Entity
@Table(name = "cases", schema = vsm)
public class CaseEntity {

    @Column(name = "id", nullable = false)
    protected Long id;

    @Column(name = "description", nullable = false)
    protected String description;
}

And I have a cases dto like this:

public class CasesDto{

    protected Long id;

    protected String description;

    private List<MemberDto> members;
}

And MemberDto the same as entity.

I need to make a mapping with mapstruct like this:

CasesDto mapToDto(CaseEntity entity);

And I need to fill List members; But I can't understand how.

Sam Kilanoff
  • 188
  • 2
  • 15
  • Would it help if you add `@OneToMany(mappedBy = "case") List members` in `CaseEntity`? Or is that something you don't want to do? – Stefan Golubović Dec 14 '19 at 13:15
  • No I don't want to add any new annotations to my entyties. Is that only solution? – Sam Kilanoff Dec 14 '19 at 16:45
  • Currently, I don't have any other ideas. It's either fetching too much data or produces the `N+1` query. If you need `MemberEntity`s in `CaseEntity`, I would consider adding the other side of [`@ManyToOne` relationship](https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/) in `CaseEntity` and [`join fetch`](https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy/) them together. – Stefan Golubović Dec 15 '19 at 14:15
  • You can have a mapper like this: CasesDto mapToDto(CaseEntity entity, List members); and then specify mappings manually. – Sanket Patel Dec 19 '19 at 09:52

1 Answers1

2

You can't just simply map it to CasesDto this way. There is no collection to be mapped to List<MemberDto>. You should rather have fully composed CaseEntity which includes:

  @OneToMany(mappedBy = "cases")
  private List<MemberEntity> members = new ArrayList<>();

To avoid worst case N+1 issue (stackOverflow N+1) you should have JPA properly configured (short spring .yml example) which would allow you to have 1 + Math.ceil({MembersAmount}/{default_batch_fetch_size}) queries executed by ORM:

spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 50
        default_batch_fetch_size: 50

Or get the list of members with your additional query and merge it within Mapstruct this way (which I consider as a worse alternative):

  @Mapping(target = "members", source = "members")
  CasesDto toDto(CaseEntity entity, List<MemberEntity> members);
Mykola Korol
  • 638
  • 6
  • 10