• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Hibernate, relacje - Błąd zapisu lub nie dodawanie id rodzica przy dziecku

Object Storage Arubacloud
0 głosów
204 wizyt
pytanie zadane 29 sierpnia 2019 w Java przez Bartek Kotarski Początkujący (480 p.)

Dzień dobry,

Mam mały problem z hibernate. Posiadam 3 klasy. które mapuję do MySql. Chce utworzyć relacje jeden do wielu (Boss- User), tak więc User musi przechowywać w  tabeli id Boss-a. Dodaje więc do bazy danych Bossa, następnie tworze użytkownika (User) i przypisuje mu wcześniej stworzonego/zapisanego Bossa po czym zapisuje User-a do bazy i dostaje taki błąd "org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.note.models.Boss". 

Niby oczywiste, ale przecież jako pierwszego dodaje Bossa, a potem Usera !

W Bossie ustawiony jest parametr Cascade = Cascade.All .

Mogę więc dodać Usera na podstawie Bossa 

boss.getUserSet().add(user);

wtedy nie ma błędu, ale User w tabeli nie zapisuje Id bossa. 

Już zgłupiałem kompletnie, wie może ktoś co robię nie tak ? 

@MappedSuperclass
public abstract class Person implements Serializable {

    @Column(nullable = false,unique = true)
    private String nick;

    @Column(nullable = false)
    private String password;

    public Person() {
    }

    public Person(String nick, String password) {
        this.nick = nick;
        this.password = password;
    }

    public String getNick() {
        return nick;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public boolean equals(Object o) {

        return this.nick.equals(((Person) o).nick);
    }
}



@Entity
@Table(name = "BOSS")
public class Boss extends Person {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOSS_SEQ")
    @SequenceGenerator(name = "BOSS_SEQ", sequenceName = "BOSS_SEQUENCE",initialValue=0, allocationSize=1)
    protected long bossId;

    @OneToMany(mappedBy = "boss",cascade = CascadeType.ALL)
    private List<User> userSet = new ArrayList<>();

    public Boss() {
    }

    public long getBossId() {
        return bossId;
    }

    public void setBossId(long bossId) {
        this.bossId = bossId;
    }

    public List<User> getUserSet() {
        return userSet;
    }

    public void setUserSet(List<User> userSet) {
        this.userSet = userSet;
    }
}




@Entity
@Table(name = "USER")
public class User extends Person
{

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ")
    @SequenceGenerator(name = "USER_SEQ", sequenceName = "USER_SEQUENCE",initialValue=0, allocationSize=1)
    private long userId;

    @OneToMany(mappedBy = "user_id",cascade = CascadeType.ALL)
    private Set<Note> listNote = new TreeSet<>();


    @ManyToOne
   // @Column(nullable = false)
    private Boss boss;

    public User() {
    }

    public User(String nick, String password) {
        super(nick, password);
    }

    public long getUserId() {
        return userId;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }


    public Boss getBoss() {
        return boss;
    }

    public void setBoss(Boss boss) {
        this.boss = boss;
    }

    public Set<Note> getListNote() {
        return listNote;
    }

    public void setListNote(Set<Note> listNote) {
        this.listNote = listNote;
    }



}


public class Main
{
    public static void main(String[] args)
    {

        Boss boss = new Boss();
        boss.setNick("Proba");
        boss.setPassword("password");
        Boss boss2 = new Boss();
        boss2.setNick("Proba2");
        boss2.setPassword("password2");

        User user = new User();
        user.setNick("Test");
        user.setPassword("password");
        user.getListNote().add(new Note("Ala ma kota",user));

        //boss.getUserSet().add(user);
        MainDao.saveInDataBase(boss);
        MainDao.saveInDataBase(boss2);

        user.setBoss(boss);
        MainDao.saveInDataBase(user);

    }
    
}

 

1
komentarz 29 sierpnia 2019 przez mbabane Szeryf (79,280 p.)
Pokaz saveInDataBase
komentarz 29 sierpnia 2019 przez Bartek Kotarski Początkujący (480 p.)
public class Connection {

    private final static SessionFactory sessionFactory;

    static
    {
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(serviceRegistry).addAnnotatedClass(User.class).addAnnotatedClass(Note.class).addAnnotatedClass(Boss.class).buildMetadata().buildSessionFactory();
    }

    static SessionFactory getSessionFactory() {
        return sessionFactory;
    }




}



public class MainDao {

    public static void saveInDataBase(Serializable serializable)
    {
        try(Session session = Connection.getSessionFactory().openSession()){
            session.beginTransaction();
            session.saveOrUpdate(serializable);
            session.getTransaction().commit();


        }catch (Exception e)
        {
            e.printStackTrace();
            Connection.getSessionFactory().openSession().getTransaction().rollback();
        }
    }

    public static <T extends Serializable> T dropFromDataBase(Class<T> cls, long id)
    {
        try(Session session = Connection.getSessionFactory().openSession()){
            return session.get(cls,id);
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

}

 

komentarz 30 sierpnia 2019 przez Aisekai Nałogowiec (42,190 p.)
Propos struktury w bazie danych. Zastanowilbym się, czy jest sens dodawania tabeli Boss, w chwili gdy Boss też jest userem. Wtedy mógłbyś zrobić tak, że robisz powiązanie tabeli samej z sobą (łatwiej bedziesz miał też rozwiązać sytuację gdy User może być też Bossem) - w sytuacji Many To Many, analogicznie tylko dodatkowa tabela w której przechowujesz oba Id.
komentarz 10 września 2019 przez Bartek Kotarski Początkujący (480 p.)
Tak dokładnie, dziękuję za radę. W nowej wersji już poprawiłem.

1 odpowiedź

0 głosów
odpowiedź 30 sierpnia 2019 przez Bartek Kotarski Początkujący (480 p.)
Problem rozwiązany, dzięki Maniak !

W metodzie saveInDataBase zamykałem transakcje po każdym zapisie, więc hibernate już nie śledził obiektów typu Boss stąd prosił o zapis bo nie sprawdzał czy takowe już są.
1
komentarz 30 sierpnia 2019 przez mbabane Szeryf (79,280 p.)
Zrozumienie mechanizmu transakcji jest wydaje mi się najbardziej kluczową rzeczą jeśli chodzi o hibernate. Warto na to poświęcić jak najwięcej czasu.

Jeszcze na marginesie metoda equals w klasie Person nie jest do koca dobrze zrobiona. Poczytaj jak to należy robić dobrze. Twoja wersja może powodować ClassCastException lub NullPointerException. Należy także przesłonić metodę hashCode jeśli tworzysz własną metodę equals
komentarz 10 września 2019 przez Bartek Kotarski Początkujący (480 p.)

Dziękuję za zwrócenie uwagi ! Czy podejście zaprezentowane poniżej jest lepsze ? (Na początku była klasa Person, teraz zastąpiła ją klasa User, którą rozszerza klasa Boss)

 

@Override
public boolean equals(Object o){
    if (o instanceof User){
        User user = (User) o;
        return personId == user.personId && nick.equals(user.nick);
    }
    return false;
}

@Override
public int hashCode() {
    return 31 * password.hashCode() + 37 * nick.hashCode();
}

 

Podobne pytania

0 głosów
0 odpowiedzi 192 wizyt
pytanie zadane 7 lipca 2016 w Java przez shimizu Obywatel (1,650 p.)
0 głosów
1 odpowiedź 185 wizyt
pytanie zadane 23 grudnia 2019 w Java przez Uwegi Początkujący (430 p.)
0 głosów
1 odpowiedź 824 wizyt
pytanie zadane 6 grudnia 2018 w Java przez Moras Obywatel (1,620 p.)

92,555 zapytań

141,402 odpowiedzi

319,553 komentarzy

61,939 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...