I am on my first Quarkus project based on quarkus-resteasy-reactive.
I have managed so far to get the basic operations working but I'm stuck on recording linked information in many to many.
Basically I have a :
@Entity
@Cacheable
public class Fiestar extends PanacheEntity {
@Column(length = 250, unique = true, nullable = false)
public String mail;
@Column(length = 50, unique = true, nullable = false)
public String phone;
@Column(length = 150, unique = true)
public String nickname;
@Column(length = 250, nullable = false)
public String password;
@Column(length = 250)
public String salt;
@ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
@JoinTable(name = "fiesta_fiestar",
joinColumns = @JoinColumn(name = "fiestar_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "fiesta_id", referencedColumnName = "id"))
public List<Fiesta> fiestasInvite;
@Column
public boolean isRememberToday = true;
@Column
public boolean isRememberDayBefore = false;
@Column
public boolean isRememberWeekBefore = false;
@Column
public boolean isAdmin = false;
@Column
public String calendarId;
public Fiestar(Long id) {
this.id = id;
}
public Fiestar() {
}
}
and an entity:
@Entity
@Cacheable
public class Fiesta extends PanacheEntity {
@Column(length = 250, nullable=false)
public String title;
@Column(nullable = false)
public LocalDateTime startDate;
@Column
public LocalDateTime endDate;
@Column
public String address;
@Column(length = 500)
public String description;
@JoinColumn(name = "creator_id")
@ManyToOne
public Fiestar creator;
@ManyToMany(mappedBy = "fiestasInvite", fetch = FetchType.EAGER)
public List<Fiestar> guests;
public Fiesta(Long id) {
this.id = id;
}
public Fiesta() {
}
}
related by the entity:
@Entity(name = "fiesta_fiestar")
@Cacheable
public class FiestaFiestar extends PanacheEntity {
@JoinColumn(name = "fiesta_id")
@ManyToOne
public Fiesta fiesta;
@JoinColumn(name = "fiestar_id")
@ManyToOne
public Fiestar fiestar;
@Column
public boolean isComing = false;
@Column
public boolean isMaybeComing = true;
@Column
public boolean isNotComing = false;
@Column
public boolean isTakingCar = false;
@Column
public boolean isAllowToInvite = false;
@Column
public String carFrom;
}
What I am trying to do is very basic as I am simply trying to persist a Fiesta and once that is done persist the guest list associated with it (pre-existing Fiestars).
Problem: The Fiesta is well persisted but not the relationship FiestaFiestar.
So far I have tried three methods:
- Panach.withTransaction( =>
public Uni<Fiesta> createFiesta(FiestaDto fiesta) {
Fiesta fiestaToPersist = fiestaMapper.toEntity(fiesta);
Log.debug(String.format("mapped fiesta = %s", fiestaToPersist.title));
Log.debug(String.format("Fiesta guest number %s", fiesta.getGuests().size()));
return Panache.withTransaction(() -> fiestaToPersist.<Fiesta>persist()
.onItem().ifNotNull().call(fiestaCreated -> {
Log.debug("Currently ion the call methode");
Log.debug("isNotEmpty(fiesta.getGuests()) " + CollectionUtils.isNotEmpty(fiesta.getGuests()));
Log.debug("isNotEmpty(fiesta.getShops()) " + CollectionUtils.isNotEmpty(fiesta.getShops()));
Log.debug("fiestaCreated.isPersistent() " + fiestaCreated.isPersistent());
if (CollectionUtils.isNotEmpty(fiesta.getGuests())) {
var fiestarIds = fiesta.getGuests().stream().map(FiestarDto::getId).toList();
Fiestar.<Fiestar>list("id in ?1", fiestarIds).onItem()
.ifNotNull()
.invoke(fiestars -> {
Log.debug(String.format("mapping %s guests with fiesta : %s", fiestars.size(), fiestaToPersist.id));
List<FiestaFiestar> guests = new ArrayList<>();
fiestars.forEach(guest -> {
FiestaFiestar newGuest = new FiestaFiestar();
newGuest.fiesta = fiestaCreated;
newGuest.fiestar = guest;
guests.add(newGuest);
Log.debug(String.format("Guest list : Size => %s, guest => %s", guests.size(), guest.toString()));
});
FiestaFiestar.persist(guests)
.onItem().ifNotNull().invoke(() -> {
Log.debug("One Guest is persist");
fiestaCreated.guests = guests.stream().map(x -> x.fiestar).toList();
})
.onItem().ifNull().failWith(() -> new RuntimeException("Fail to persist guests :\\n"));
}).onItem().ifNull().failWith(() -> new RuntimeException("Guests not found !"));
}
}
- Uni.createFrom() :
@WithTransaction
public Uni<Fiesta> persistEntity(FiestaDto fiestaDto) {
Fiesta fiestaToPersist = fiestaMapper.toEntity(fiestaDto);
Log.debug(String.format("mapped fiesta = %s", fiestaToPersist.title));
Log.debug(String.format("Fiesta guest number %s", fiestaDto.getGuests().size()));
return Uni.createFrom().item(() -> {
fiestaToPersist.persist();
if (CollectionUtils.isNotEmpty(fiestaDto.getGuests())) {
Log.debug(String.format("mapping %s guests with fiesta : %s", fiestaDto.getGuests().size(), fiestaToPersist.id));
List<FiestaFiestar> guests = new ArrayList<>();
fiestaDto.getGuests().forEach(guest -> {
var guestToAdd = new FiestaFiestar();
guestToAdd.fiesta = fiestaToPersist;
guestToAdd.fiestar = new Fiestar(guest.getId());
guests.add(guestToAdd);
Log.debug(String.format("Guest list : Size => %s, guest => %s", guests.size(), guest.getId()));
guestToAdd.persist();
});
}
return fiestaToPersist;
});
And finally to persist first the Fiesta and then to add guests:
public Uni<Fiesta> addGuest(GuestToAddPayload payload) { Panache.withTransaction(() -> { Fiesta.findById(payload.getFiestaId()) .replaceIfNullWith(() -> { throw new RuntimeException("Fiesta not found"); }).onItem() .transform(foundFiesta -> { Log.debug("We got fiesta"); Fiestar.list() }) payload.getGuestIds().forEach(fiestarId -> { FiestaFiestar guest = new FiestaFiestar(); guest.fiesta = new Fiesta(payload.getFiestaId()); guest.fiestar = new Fiestar(fiestarId); guest.persist(); }); return null; }); }
Unfortunately, all three attempts ended with the same answer... No persistent links.
So I guess I'm not using the asynchronous operation of the library correctly.
I've tried to find an example of such a relationship in the Quackus documentation.
Thanks to all !