OneToMany i zwracanie id

0

Mam dwie encję User i Task w relacji OneToMany. Chciałbym z metody, która dodaje taska do usera zwracać id tego taska, ale zwracany jest null (id w bazie zapisuje się normalnie).

@RequiredArgsConstructor
class CreateTaskHandler {

private final UserRepository userRepository;
private final TaskContentValidator taskContentValidator;

@Transactional
Either<TaskError, TaskDto> handle(CreateTask command) {
   return userRepository.getByUsername(command.getUsername())
            .map(user -> taskContentValidator.validate(command.getContent())
                    .map(correctContent -> new Task(correctContent, command.getPriority(), command.getStatus(), user))
                    .map(task -> user.addTask(task))
                    .map(addedTask -> new TaskDto(addedTask.getId())))
            .getOrElseThrow(() -> new UserNotFoundException(command.getOwnerUsername()));
   }
}
0

Jeśli nie masz konieczności generowania ID przez bazę proponowałbym robić to z poziomu aplikacji. Nie będziesz miał wtedy problemu, a encje będą też mogłby być niemutowalne.

new Task(randomUUID(), correctContent, command.getPriority(), command.getStatus(), user)

Aktualnie tworzysz "ręcznie" obiekt, a Hibernate w tle wrzuci go do bazy i wygeneruje identyfikator. Tutaj magicznie nie dostaniesz niestety id.

0

@VeloxDigitis: Chcę używać id generowanego przez bazę, bo to prostka apka i sensowniej w niej jest używać id typu 1,2 itd. niż kilkunastu znakowych uuidów.
Myślałem jeszcze, żeby użyć po prostu oddzielnego repo dla tasków. Wtedy przy zapisie zwracany byłby task z już wygenerowanym id. Co o tym sądzisz?

0
VeloxDigitis napisał(a):

Jeśli nie masz konieczności generowania ID przez bazę proponowałbym robić to z poziomu aplikacji. Nie będziesz miał wtedy problemu, a encje będą też mogłby być niemutowalne.

new Task(randomUUID(), correctContent, command.getPriority(), command.getStatus(), user)

Aktualnie tworzysz "ręcznie" obiekt, a Hibernate w tle wrzuci go do bazy i wygeneruje identyfikator. Tutaj magicznie nie dostaniesz niestety id.

Bezpieczne wątkowo TYLKO przez miliardową przestrzeń UUID.
W przypadku ogólnym generowanie kluczy w aplikacji wcale miodem nie jest.

Sampeteq napisał(a):

@VeloxDigitis: Chcę używać id generowanego przez bazę, bo to prostka apka i sensowniej w niej jest używać id typu 1,2 itd. niż kilkunastu znakowych uuidów.
Myślałem jeszcze, żeby użyć po prostu oddzielnego repo dla tasków. Wtedy przy zapisie zwracany byłby task z już wygenerowanym id. Co o tym sądzisz?

Pozwól mi wejść miedzy wódkę i zakąski ...
Robiłem nie takie małe projekty w JPA, i nigdy nie pojawiła się POTRZEBA znajomości ID (oczywiście jest znana po zapisie)
JPA całkiem dobrze zapisuje sieci powiązanych OBIEKTOWO obiektów, wystarczy mu nie przeszkadzać.

Może się wcinam między j/w, ale nie ściągnąłeś sobie problemu sam?
Na przykład przez niby używanie Hibernate z myśleniem SQL-owym (zawsze dziwne dla mnie) , w szczególności property wskazujące na "ten drugi obiuekt" nie obiektowe, a integer ?
Mówię o

class Task {
   int userId;
}

vs

class Task {
   User user;;
}

Wyższym stadium tej samej choroby są zbyt poszatkowane repozytoria, to tylko sposób na pogłębienie prblemu.

Jak chcieć kompletować grupy rekordów ręcznie, panować nad tym na sposób SQL-a - ja bym użył innego toola niż Hibernate, niskopoziomowego mappera

2
.map(correctContent -> new Task(correctContent, command.getPriority(), command.getStatus(), user))
.map(task -> user.addTask(task))
.map(addedTask -> new TaskDto(addedTask.getId())))

Ale skąd Ty chcesz mieć to id? Przeciez to nie może działać. Przecież w czasie transakcji task będzie widziany jako obiekt w stanie Transient. Ten spoósb nie działa, po prostu.

0

Spróbuj zrobić tak:

.map(task -> { 
  var addedTask = user.addTask(task);
  userRepository.flush();
  return addedTask;
})
...

Możesz też spróbować zwrócić encje Task i gdzieś “wyżej” zrobić konwersję do dto. Możesz również spróbować użyć TransactionTemplate i ręcznie wykonać transakcję.

1 użytkowników online, w tym zalogowanych: 0, gości: 1