У меня стандартное отношение многие ко многим в Spring с постоянством использования Hibernate. Конструкторы и сеттеры оставлены для краткости.
@Entity
@Table(name = "a")
public class A {
@ManyToMany(mappedBy = "as")
private Set<B> bs;
}
@Entity
@Table(name = "bs")
public class B {
@ManyToMany
@JoinTable(
name = "b_a",
joinColumns = @JoinColumn(name = "b_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id")
)
private Set<A> as = new HashSet<>();
}
У меня также есть DTO для каждого из этих классов, и у меня есть методы c для передачи между ними. В связи с отношением «многие ко многим» мне нужно реализовать форму отслеживания состояния, чтобы не допустить попадания программы в бесконечную рекурсию.
public final class DTOEntityMapper {
private static class StateHolder {
private List<Object> alreadySeenObjects = new ArrayList<>();
void addObject(Object o){
alreadySeenObjects.add(o);
}
boolean contains(Object o){
return alreadySeenObjects.contains(o);
}
}
public static BDTO fromBToDTO(B b) {
return fromBToDTO(b, new StateHolder());
}
private static BDTO fromBToDTO(B b, StateHolder state) {
state.addObject(b);
return BDTO.builder()
.withAs(b.getAs().stream().filter(item -> !state.contains(item)).map(e -> fromAToDTO(e, state)).collect(Collectors.toSet()))
.build();
}
}
// Note: fromAToDTO does same thing.
Однако, когда я пытаюсь протестировать, я получаю ошибку утверждения:
@Test
public void convertFromBToBDTO() {
A a = new A("a");
B b = new B("b");
b.setAs(ImmutableSet.of(a));
a.setBs(ImmutableSet.of(b));
aDTO ADTO = new ADTO("a");
bDTO BDTO = new BDTO("b");
bDTO.setAs(ImmutableSet.of(aDTO));
aDTO.setBs(ImmutableSet.of(bDTO));
BDTO expected = bDTO;
assertThat(DTOEntityMapper.fromBToDTO(b)).isEqualTo(expected);
}
Actual: BDTO{as=[ADTO{bs=}]}
Expected: BDTO{as=[ADTO{bs=b1}]}
По сути, меня смущает то, как я отношусь к отношениям "многие ко многим" при преобразовании между моделью данных и DTO. Надеюсь, это имеет смысл!