Hibernate - problem z tabelą łącznikową

0

Witam

Mam problem jak odwzorować tabele łącznikową:

1 tabela - Ososby (id_osoby PK, imie, nazwisko)
2 tabela - Miesiace (id_miesiaca PK, nazwa)
3 tabela - Wyplaty ( {id_osoby, id_miesiaca} PK , stawka, l_godz)

Mam odwzorowane tabele Osoby i Miesiace i nie wiem jak odwzorować tabeli wypłaty. Jeśli byłaby to tabela łącznikowa tylko z tymi dwoma id to nie byłoby problemu, nie trzeba było by jej odwzorowywać, jednak gdy mamy w niej dodatkowe kolumny pojawia się problem.

Zrobiłem taką klasę w java

public class Wyplaty {

private int l_godz;
private double stawka;
private Miesiace miesiace;
private Osoby osoby;

public Wyplaty {
}

public Wyplaty(int l_godz, double stawka, Miesiace miesiace, Osoby osoby) {
    this.l_godz = l_godz;
    this.stawka = stawka;
    this.miesiace = miesiace;
    this.osoby = osoby;
}

public Osoby getOsoby() {
    return osoby;
}

public void setOsoby(Osoby osoby) {
    this.osoby = osoby;
}

public Miesiace getMiesiace() {
    return miesiace;
}

public void setMiesiace(Miesiace miesiace) {
    this.mesiace = miesiace;
}

public double getStawka() {
    return stawka;
}

public void setStawka(double stawka) {
    this.stawka = stawka;
}


public int getL_godz() {
    return l_godz;
}


public void setL_godz(int l_godz) {
    this.l_godz = l_godz;
}

}

teraz mam problem z odwzorowaniem tego w pliku hbm.xml

<hibernate-mapping> <class name="wyplaty.Wyplaty" table="Wyplaty">
<composite-id>

?????????????????????????????????????????
</composite-id>

<property column="l_godz" name="l_godz" type="int"/>
<property column="stawka" name="stawka" type="double"/>

<many-to-one class="wyplaty.Osoby" column="osoby" foreign-key="FK_Wyplaty_Osoby" name="osoby" not-null="true"/>
<many-to-one class="wyplaty.Miesiace" column="id_miesiaca" foreign-key="Wyplaty_Miesiace" name="Miesiace" not-null="true"/>
</class> </hibernate-mapping>

Nie wiem jak określić klucz główny przy odwzorowaniu tej tabeli

Bardzo prosiłbym o podpowiedź

0

Mozesz tak:

  • klasa Osoba i Miesiac maja kolekcje obiektow Wyplata, kolekcje te sa inverse="true", poniewaz to Wyplata bedzie wlascicielem tych kolekcji, i ja bedziesz zapisywal do bazy
  • klasa Wyplata ma many-to-one do Miesiac i Osoba, one maja inserte="false" i update="false", a sama encja jest mutable="false"
  • mapowana jest do osobnej tabeli, i jej klucz wyglada jakos tak:
    <composite-id name="id" class="WyplataId">
    <key-property name="osobaId" access="field" column="OSOBA_ID" />
    <key-property name="MiesiacId" access="field" column="MIESIAC_ID" />
    </composite-id>
    Czyli takie zlozone klucze musza miec wlasna klase, ktora wkazujesz. Teraz zapisywanie:

Osoba o = new Osoba(...);
Miesiac m = new Miesiac(...);
Wyplata w = new Wyplata(o, m, l_godzin, stawka);
session.save(w); // jako ze wyplata jest wlascicielem kolekcji (pamietasz many-to-one ustawione na inverse="true" w Osoba i Miesiac?), z wlaczonym kaskadowaniem zapisu hibernate zapisze obiekt wyplata w tabeli, i zapisze osobe i miesiac (lub tylko klucze do nich, jesli sa juz w bazie).
Przy pobieraniu danych mozesz referencje do osoby i miesiaca ustawic na lazy lub nie, i nawigacja wyglada mniej wiecej tak (dla java.util.List) (majac obiekty osoby lub miesiaca):
miesiac.getWyplaty().get(0).getOsoba() lub osoba.getWyplaty().get(0).getMiesiac()

Cos w ten desen. Pamietaj o kaskadowaniu i kolekcjach lazy, ale to juz inny temat.

0

Dalej nie mogę sobie z tym poradzić wrzucę teraz klasy i mapowania dokładnie programiku który robię bo różni się on trochę od tego co podałem w pierwszym poście:

Roboty 1..* Pracownicy_roboty *..1 Pracownicy
id_roboty id_roboty id_pracownika
id_miesiaca id_pracownika imie
nazwa l_godz nazwisko
stawka aktywny

Pracownicy.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="wyplaty.Pracownicy" table="Pracownicy">
    <id column="id_pracownika" name="id_pracownika" type="int">
      <generator class="native"/>
    </id>
   
    <set name="pracownicy_wyplata" table="Pracownicy_roboty" inverse="true">
        <key column="id_pracownika" foreign-key="FK_Pracownicy_roboty_Pracownicy"/>
        <many-to-many class="wyplaty.Roboty" column="id_roboty"
            foreign-key="FK_Pracownicy_roboty_Roboty"/>
    </set>
    <property column="imie" name="imie" type="string"/>
    <property column="nazwisko" name="nazwisko" type="string"/>
    <property column="aktywny" name="aktywny" type="boolean"/>
  </class>
</hibernate-mapping>

Pracownicy.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wyplaty;
import java.util.*;
/**
 *
 * @author Malak
 */
public class Pracownicy {

    private String imie;
    private String nazwisko;
    private int id_pracownika;
    private boolean aktywny;
    private Set pracownicy_wyplata = new HashSet();
    

    public Pracownicy(String imie, String nazwisko, boolean aktywny) {
        this.imie = imie;
        this.nazwisko = nazwisko;
        this.aktywny = aktywny;
        this.pracownicy_wyplata = new HashSet();
    }

    private Pracownicy(){
    }

    public Set getPracownicy_wyplata() {
        return pracownicy_wyplata;
    }

    public void setPracownicy_wyplata(Set pracownicy_wyplata) {
        this.pracownicy_wyplata = pracownicy_wyplata;
    }
    
    public int getId_pracownika() {
        return id_pracownika;
    }

    public void setId_pracownika(int id_pracownika) {
        this.id_pracownika = id_pracownika;
    }

    public boolean isAktywny() {
        return aktywny;
    }

    public void setAktywny(boolean aktywny) {
        this.aktywny = aktywny;
    }

    
    public String getNazwisko() {
        return nazwisko;
    }

    public void setNazwisko(String nazwisko) {
        this.nazwisko = nazwisko;
    }

    public String getImie() {
        return imie;
    }

    public void setImie(String imie) {
        this.imie = imie;
    }

}

Roboty.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="wyplaty.Roboty" table="Roboty">
    <id column="id_roboty" name="id_roboty" type="int">
      <generator class="native"/>
    </id>
    <set name="pracownicy_wyplata" table="Pracownicy_roboty" inverse="true">
        <key column="id_roboty" foreign-key="FK_Pracownicy_roboty_Roboty"/>
        <many-to-many class="wyplaty.Pracownicy" column="id_pracownika"
            foreign-key="FK_Pracownicy_roboty_Pracownicy"/>
    </set>
    <property column="nazwa" name="nazwa" type="string"/>
    <many-to-one class="wyplaty.Miesiace" column="id_miesiaca" foreign-key="FK_Roboty_miesiace" name="miesiace" not-null="true"/>
  </class>
</hibernate-mapping>

Roboty.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wyplaty;
import java.util.*;

/**
 *
 * @author Malak
 */
public class Roboty {

    private int id_roboty;
    private String nazwa;
    private Miesiace miesiace;
    private Set pracownicy_wyplata = new HashSet();

    public Roboty(String nazwa, Miesiace miesiace) {
        this.nazwa = nazwa;
        this.miesiace = miesiace;
        this.pracownicy_wyplata = new HashSet();
    }
    
    public Roboty() {
    }

    public Set getPracownicy_wyplata() {
        return pracownicy_wyplata;
    }

    public void setPracownicy_wyplata(Set pracownicy_wyplata) {
        this.pracownicy_wyplata = pracownicy_wyplata;
    }

    public Miesiace getMiesiace() {
        return miesiace;
    }

    public void setMiesiace(Miesiace miesiace) {
        this.miesiace = miesiace;
    }

    public String getNazwa() {
        return nazwa;
    }

    public void setNazwa(String nazwa) {
        this.nazwa = nazwa;
    }

    public int getId_roboty() {
        return id_roboty;
    }

    public void setId_roboty(int id_roboty) {
        this.id_roboty = id_roboty;
    }

}

Pracownicy_roboty.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="wyplaty.Pracownicy_roboty" table="Pracownicy_roboty" mutable="false">
    <composite-id name="id" class="wyplaty.Pracownicy_roboty_PK">
        <key-property name="id_pracownika"
            access="field"
            column="id_pracownika"/>
        <key-property name="id_roboty"
            access="field"
            column="id_roboty"/>
    </composite-id>
    <property column="l_godz" name="l_godz" type="int"/>
    <property column="stawka" name="stawka" type="double"/>
    <many-to-one 
        class="wyplaty.Pracownicy" 
        column="id_pracownika" 
        foreign-key="FK_Pracownicy_roboty_Pracownicy" 
        name="pracownicy" 
        not-null="true" 
        insert="false"
        update="false"/>
    <many-to-one 
        class="wyplaty.Roboty" 
        column="id_roboty" 
        foreign-key="FK_Pracownicy_roboty_Roboty" 
        name="roboty" 
        not-null="true"
        insert="false"
        update="false"/>
  </class>
</hibernate-mapping>

Pracownicy_roboty.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wyplaty;

/**
 *
 * @author Malak
 */
public class Pracownicy_roboty {

    private int l_godz;
    private double stawka;
    private Roboty roboty;
    private Pracownicy pracownicy;

    public Pracownicy_roboty() {
    }

    public Pracownicy_roboty(int l_godz, double stawka, Roboty roboty, Pracownicy pracownicy) {
        this.l_godz = l_godz;
        this.stawka = stawka;
        this.roboty = roboty;
        this.pracownicy = pracownicy;
    }

    public Pracownicy getPracownicy() {
        return pracownicy;
    }

    public void setPracownicy(Pracownicy pracownicy) {
        this.pracownicy = pracownicy;
    }

    public Roboty getRoboty() {
        return roboty;
    }

    public void setRoboty(Roboty roboty) {
        this.roboty = roboty;
    }

    public double getStawka() {
        return stawka;
    }

    public void setStawka(double stawka) {
        this.stawka = stawka;
    }


    public int getL_godz() {
        return l_godz;
    }


    public void setL_godz(int l_godz) {
        this.l_godz = l_godz;
    }

}

Pracownicy_roboty_PK.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wyplaty;

/**
 *
 * @author Malak
 */
public class Pracownicy_roboty_PK {

    private int id_roboty;
    private int id_pracownika;

    public Pracownicy_roboty_PK() {
    }

    public Pracownicy_roboty_PK(int id_roboty, int id_pracownika) {
        this.id_roboty = id_roboty;
        this.id_pracownika = id_pracownika;
    }

    public int getId_roboty() {
        return id_roboty;
    }

    public void setId_roboty(int id_roboty) {
        this.id_roboty = id_roboty;
    }

    public int getId_pracownika() {
        return id_pracownika;
    }

    public void setId_pracownika(int id_pracownika) {
        this.id_pracownika = id_pracownika;
    }

}

Wygląda to tak. Podczas parsowania Pracownicy_roboty.hbm.xml pojawia się taki błąd

WARNING: composite-id class does not override hashCode(): wyplaty.Pracownicy_roboty_PK
Exception in thread "main" org.hibernate.MappingException: composite-id class must implement Serializable: wyplaty.Pracownicy_roboty_PK
        at org.hibernate.mapping.RootClass.checkCompositeIdentifier(RootClass.java:220)
        at org.hibernate.mapping.RootClass.validate(RootClass.java:201)
        at org.hibernate.cfg.Configuration.validate(Configuration.java:1102)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1287)
        at wyplaty.Main.main(Main.java:28)

Nie wiem co teraz zrobic. Myśle ze mam błędy w tym pliku. Nie wiem także czy określiłem dobrze PK dla tej tabeli i czy ją się odwzorowuje w hbm.xml. Proszę o przejrzenie kodu i naniesienie poprawek. Z góry bardzo dziekuję:)

0

No przede wszystkim komunikat mowi ze klasa klucza podst ktora utworzyles nie jest Serializable, i faktycznie nie jest, wiec zmien to dodajac "implements Serializable" po nazwie klasy.
Po drugie, Roboty i Pracownicy nie maja miec mapowac many-to-many do Pracownicy i Roboty, lecz obie maja miec kolekcje (set, list, cokolwiek, z one-to-many) do Pracownicy_Roboty.
Sprawdz jak to sie zachowa.
Aha, takie rady - czytaj komunikaty. Oraz zastanow sie czy nie mozesz uzywac angielskiego jako jezyk kodowania. Niespecjalnie mi to przeszkadza, ale w pracy prawdopodobnie bedziesz musial tak czy tak uzywac angielskich nazw, a i set_pracownicy a setEmployers jakos mi sie bardziej podoba.

0

Wielkie dzięki, tak działa

Ale mam jeszcze pytanie, zrobiłem tak jak mówiłes i jak pierwszy raz uruchomiłem wystąpił taki błąd:
ids for this class must be manually assigned before calling save(): wyplaty.Pracownicy_roboty

czyli trzeba samemu ustawiać id, tak jak zrobiłem to tytaj:

Pracownicy_roboty pr = new Pracownicy_roboty(Integer.parseInt(p1_godziny1.getText()), Double.parseDouble(p1_stawka1.getText()), lista_robot[0], pracownik);
    Pracownicy_roboty_PK pk = new Pracownicy_roboty_PK(lista_robot[0].getId_roboty(), pracownik.getId_pracownika());
    pr.setId(pk);
    k.zapisz_stawki(pr);

Trochę mnie to zastanawia ze hibernate nie potrafi sam tego ustawić, da się to jakoś zautomatyzować aby nie trzeba było robić tego ręcznie??

0

Jak w koncu zrobiles? Zmieniles tylko dodajac Serializable czy jeszcze zrobiles pozostale czynnosci? Ciekawi mnie, a i inni szukajacy beda mogli sie dowiedziec.
Co do tych id, to chyba ine da sie inaczej skoro hibernate prosi ;-) Skad ma wiedziec jakie kolumny ma tam wstawic? Niby powinien wiedziec ze id no ale jakos nie wie ;-)

0

Zrobiłem to tak jak pisałeś. Najpierw dodałem Serializable

public class Pracownicy_roboty_PK implements Serializable

Potem do Pracownicy_roboty.java dodałem: private Pracownicy_roboty_PK id; oczywiście z setterami i getterami

Nastepnie w 3 plikach wprowadziłem zmiany:

Pracownicy_roboty.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class mutable="false" name="wyplaty.Pracownicy_roboty" table="Pracownicy_roboty">
    <composite-id class="wyplaty.Pracownicy_roboty_PK" name="id">
      <key-property access="field" column="id_pracownika" name="id_pracownika"/>
      <key-property access="field" column="id_roboty" name="id_roboty"/>
    </composite-id>
    <property column="l_godz" name="l_godz" type="double"/>
    <property column="stawka" name="stawka" type="double"/>
    <many-to-one class="wyplaty.Pracownicy" column="id_pracownika" foreign-key="FK_Pracownicy_roboty_Pracownicy" insert="false" name="pracownicy" not-null="true" update="false"/>
    <many-to-one class="wyplaty.Roboty" column="id_roboty" foreign-key="FK_Pracownicy_roboty_Roboty" insert="false" name="roboty" not-null="true" update="false"/>
  </class>
</hibernate-mapping>

Pracownicy.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="wyplaty.Pracownicy" table="Pracownicy">
    <id column="id_pracownika" name="id_pracownika" type="int">
      <generator class="native"/>
    </id>
    <set inverse="true" name="pracownicy_wyplata" table="Pracownicy_roboty">
      <key column="id_pracownika" foreign-key="FK_Pracownicy_roboty_Roboty"/>
      <one-to-many class="wyplaty.Pracownicy_roboty"/>
    </set>
    <property column="imie" name="imie" type="string"/>
    <property column="nazwisko" name="nazwisko" type="string"/>
    <property column="aktywny" name="aktywny" type="boolean"/>
  </class>
</hibernate-mapping>

Roboty.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="wyplaty.Roboty" table="Roboty">
    <id column="id_roboty" name="id_roboty" type="int">
      <generator class="native"/>
    </id>
    <set inverse="true" name="pracownicy_wyplata" table="Pracownicy_roboty">
      <key column="id_roboty" foreign-key="FK_Pracownicy_roboty_Roboty"/>
      <one-to-many class="wyplaty.Pracownicy_roboty"/>
    </set>
    <property column="nazwa" name="nazwa" type="string"/>
    <many-to-one class="wyplaty.Miesiace" column="id_miesiaca" foreign-key="FK_Roboty_miesiace" name="miesiace" not-null="true"/>
  </class>
</hibernate-mapping>

I to by było na tyle. Dziwi mnie jdnak ustawianie tego id:

Pracownicy_roboty pr = new Pracownicy_roboty(Integer.parseInt(p1_godziny1.getText()), Double.parseDouble(p1_stawka1.getText()), lista_robot[0], pracownik);
    Pracownicy_roboty_PK pk = new Pracownicy_roboty_PK(lista_robot[0].getId_roboty(), pracownik.getId_pracownika());
    pr.setId(pk);
    k.zapisz_stawki(pr);

Chciałem to załatwić to w konstruktorze Pracownicy_roboty, bo przecież do jego konstruktora daję obiekt pracownika i roboty, więc mam potrzebne wszystkie dane aby ustawić Pracownicy_roboty_PK ale tak się nie da :/

0

Jednak da się to ustawić.
Wystarczy w konstruktorze Pracownicy_roboty dołożyć linijke:

this.id = new Pracownicy_roboty_PK(roboty.getId_roboty(), pracownicy.getId_pracownika());

i wszystko działa:)

Dzieki jeszcze raz za pomoc:)

0

Myslalem ze chodzi ci o cos zupelnie innego z tymi przypisniami id. A co do komunikatu ktory dostales, to jest tak dlatego ze do takich id nie masz generatora (sekwencja, identity, hi-lo, ...), no i musisz sam stworzyc id i przypisac. Nie zrozumialem problemu. No ale dobrze ze dziala.

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