Unsaved transient entity instance

Unsaved transient entity instance
ZA
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:174
0

Witajcie,
Znalazłem bardzo fajny projekt na githubie i postanowiłem napisać coś na jego podstawie. Padło na prostą aplikacje gdzie można dodawać użytkowników, a do każdego użytkownika jakąś akcję. Problem w tym, że podczas pisania kodu trafiłem na błąd. Treść tego błędu jest dla mnie całkowicie zrozumiała, tak samo jak zasada działania kodu w poniższym projekcie. Problem w tym że nie mam pomysłu jak zaradzić temu błędowi i dziwię się czemu nie występuje on w wymienionym projekcie, ponieważ mój kod jest prawie identyczny.
https://github.com/spring-projects/spring-petclinic

Moje encje:

Kopiuj
@Entity
public class Action {
    @Id
    @GeneratedValue
    private Integer id;

    @Column
    private String name;

    @JoinColumn
    @ManyToOne
    private User user;

    public Integer getId() { return this.id; }
    protected void setId(Integer id) { this.id = id; }

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public void getUser() { return this.user; }
    protected void setUser(User user) { this.user = user; }
}
@Entity
public class User {
    @Id
    @GeneratedValue
    private Integer id;

    @Column
    private String name;

    @OneTomany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Action> actions = new ArrayList<>();

    public Integer getId() { return this.id; }
    protected void setId(Integer id) { this.id = id; }

    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }

    public void addAction(Action action) {
        action.setUser(this);
        actions.add(action);
    }
    public void removeAction(Action action) {
        actions.remove(action);
        action.setUser(null);
    }
    public List<Action> getActions() { return Collections.unmodifiableList(actions); }
}

Warstwa serwisowa:

Kopiuj
@Transactional(readyOnly = true)
public User getByName(String name) {
    return this.userRepository.getByName(name);
}

@Transactional
public void saveAction(Action action) {
    this.actionRepository.save(action);
}

I warstwa controller:

Kopiuj
@Controller
@RequestMapping("/user/{username}")
@SessionAttributes("user")
public class ActionController {
    @Autowired
    private TestService service;

    @ModelAttribute("user")
    public User contextRegistration(@PathVariable("username") String username) {
        return this.service.getByName(username);
    }

    @RequestMapping("")
    public String userView() {
        return "user";
    }

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String addAction(@ModelAttribute Action action) {
        return "addAction";
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String postAddAction(@Valid Action action, BindingResult result, User user, SessionStatus sessionStatus) {
        if(result.hasErrors()) {
            return "addAction";
        }

        user.addAction(action);
        // W poniższej linijce zostaje wyrzucony wyjątek
        this.service.saveAction(action);
        sessionStatus.setComplete();
        return "redirect:/user/{username}";
    }
}

Tutaj link do podobnej linijki w tym projekcie: https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/web/PetController.java#L99

No i mój bład:

Kopiuj
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : pl.zaprogramowany.test.model.Action.user -> pl.zaprogramowany.test.model.User

Macie jakiś pomysł jak temu zaradzić? Wiecie co robię źlę?

RO
Obiekt nadrzędny nie został zapisany zanim chcesz zapisać obiekt podrzędny w tym przypadku User nie został zapisany a zapisujesz Action, które się do niego odwołuje. Wrzuciłeś encje oraz serwis a, gdzie warstwa repo, gdzie prawdopodobnie się to dzieje?
ZA
Instancja Usera jest pobierana z bazy wiec musi być zapisana ww niejniej zapisana. Instancja która jest parametrem metody controllera pochodzi z metody contextRegistration. Warstwa repo to nic innego jak repozytorium springa definiowane jako interfejs gdzie Spring na podstawie nazwy metody automatycznie generuje zapytanie.
RO
  • Rejestracja:około 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:83
0

To co mi sie nasuwa: nie zapisujesz usera po dodaniu akcji. Rozumiem ze akcja ma juz ustawionego usera w momencie zaladowania tej metody z parametru user tak ? w ogole nie wiem po co jest service.saveAction skoro mozesz zapisac usera kaskadowo z nowymi akcjami (updateowac) - taki strzal // pisane z komorki
// dodalem posta zeby nie dostac opierdzielu od moderatora


Jestem początkujący.
ZA
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:174
0

Problem w tym że w kontrolerze nie mam aktywnej trasakcji, która mogła by zostać zacommitowana. Dlatego też metoda addAction doda akcje do Encji User, ale nie zostanie wykonane zapytanie.

VA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:180
0

Pozwole sobie odswierzyc temat bo mam ten sam problem problem co kolega.. i nie umiem z nim sobie poradzic.
To co chce uzyskac to przy podaniu takiego zapytania :
Projekt:

Kopiuj
{
 "name": "Testnowy",
 "owner_id": 1
 }

Zeby stworzyl sie obiet Projekt z FK owner_id. Jezeli nie istnieje user o takim owner_id to ma rzucic wyjatkiem.

Na chwile obecna mam to co kolega wyzej... ( w zaleznosci od ustawien.. zdarza mi sie tez miec blad no-constuctor int... )
Jezeli podam w tym jsonie pelnego usera, to wtedy user tez tworzy sie w bazie i to jest zdecydowanie to zachowanie ktorego nie chce.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.