Moja baza danych zawiera 3 tabele: Encje użytkowników i usług mają relację wiele do wielu i są połączone z tabelą SERVICE_USER w następujący sposób:
USERS - SERVICE_USER - SERVICES
Tabela SERVICE_USER zawiera dodatkową kolumnę BLOCKED.
Jaki jest najlepszy sposób wykonania takiego mapowania? To są moje klasy Entity
@Entity
@Table(name = "USERS")
public class User implements java.io.Serializable {
private String userid;
private String email;
@Id
@Column(name = "USERID", unique = true, nullable = false,)
public String getUserid() {
return this.userid;
}
.... some get/set methods
}
@Entity
@Table(name = "SERVICES")
public class CmsService implements java.io.Serializable {
private String serviceCode;
@Id
@Column(name = "SERVICE_CODE", unique = true, nullable = false, length = 100)
public String getServiceCode() {
return this.serviceCode;
}
.... some additional fields and get/set methods
}
Postępowałem zgodnie z tym przykładem http://giannigar.wordpress.com/2009/09/04/m ... using-jpa / Oto kod testowy:
User user = new User();
user.setEmail("e2");
user.setUserid("ui2");
user.setPassword("p2");
CmsService service= new CmsService("cd2","name2");
List<UserService> userServiceList = new ArrayList<UserService>();
UserService userService = new UserService();
userService.setService(service);
userService.setUser(user);
userService.setBlocked(true);
service.getUserServices().add(userService);
userDAO.save(user);
Problem polega na tym, że hibernacja utrzymuje się w obiekcie User i UserService. Brak powodzenia z obiektem CmsService
Próbowałem użyć pobierania EAGER - brak postępu
Czy możliwe jest osiągnięcie oczekiwanego zachowania przy użyciu powyższego mapowania?
Może istnieje bardziej elegancki sposób mapowania wielu do wielu tabeli złączeń z dodatkową kolumną?
@ElementCollection
z (lub obu) jednostek User i Service.[userFK, serviceFK]
niepowtarzalność, użyj unikalnego ograniczenia.Szukam sposobu na zmapowanie tabeli skojarzeń wiele do wielu z dodatkowymi kolumnami z hibernacją w konfiguracji plików xml.
Zakładając, że mamy dwie tabele „a” i „c” z powiązaniami wiele do wielu z kolumną o nazwie „extra”. Ponieważ nie znalazłem żadnego pełnego przykładu, oto mój kod. Mam nadzieję, że to pomoże :).
Najpierw są obiekty Java.
public class A implements Serializable{ protected int id; // put some others fields if needed ... private Set<AC> ac = new HashSet<AC>(); public A(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Set<AC> getAC() { return ac; } public void setAC(Set<AC> ac) { this.ac = ac; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 97; int result = 1; result = prime * result + id; return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof A)) return false; final A other = (A) obj; if (id != other.getId()) return false; return true; } } public class C implements Serializable{ protected int id; // put some others fields if needed ... public C(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 98; int result = 1; result = prime * result + id; return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof C)) return false; final C other = (C) obj; if (id != other.getId()) return false; return true; } }
Teraz musimy utworzyć tabelę asocjacji. Pierwszym krokiem jest utworzenie obiektu reprezentującego złożony klucz podstawowy (a.id, c.id).
public class ACId implements Serializable{ private A a; private C c; public ACId() { super(); } public A getA() { return a; } public void setA(A a) { this.a = a; } public C getC() { return c; } public void setC(C c) { this.c = c; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((a == null) ? 0 : a.hashCode()); result = prime * result + ((c == null) ? 0 : c.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ACId other = (ACId) obj; if (a == null) { if (other.a != null) return false; } else if (!a.equals(other.a)) return false; if (c == null) { if (other.c != null) return false; } else if (!c.equals(other.c)) return false; return true; } }
Teraz stwórzmy sam obiekt skojarzenia.
public class AC implements java.io.Serializable{ private ACId id = new ACId(); private String extra; public AC(){ } public ACId getId() { return id; } public void setId(ACId id) { this.id = id; } public A getA(){ return getId().getA(); } public C getC(){ return getId().getC(); } public void setC(C C){ getId().setC(C); } public void setA(A A){ getId().setA(A); } public String getExtra() { return extra; } public void setExtra(String extra) { this.extra = extra; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AC that = (AC) o; if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; return true; } public int hashCode() { return (getId() != null ? getId().hashCode() : 0); } }
W tym momencie nadszedł czas, aby zmapować wszystkie nasze klasy z konfiguracją hibernacji xml.
A.hbm.xml i C.hxml.xml (wycisz to samo).
<class name="A" table="a"> <id name="id" column="id_a" unsaved-value="0"> <generator class="identity"> <param name="sequence">a_id_seq</param> </generator> </id> <!-- here you should map all others table columns --> <!-- <property name="otherprop" column="otherprop" type="string" access="field" /> --> <set name="ac" table="a_c" lazy="true" access="field" fetch="select" cascade="all"> <key> <column name="id_a" not-null="true" /> </key> <one-to-many class="AC" /> </set> </class> <class name="C" table="c"> <id name="id" column="id_c" unsaved-value="0"> <generator class="identity"> <param name="sequence">c_id_seq</param> </generator> </id> </class>
Następnie plik mapowania skojarzeń a_c.hbm.xml.
<class name="AC" table="a_c"> <composite-id name="id" class="ACId"> <key-many-to-one name="a" class="A" column="id_a" /> <key-many-to-one name="c" class="C" column="id_c" /> </composite-id> <property name="extra" type="string" column="extra" /> </class>
Oto przykładowy kod do przetestowania.
A = ADao.get(1); C = CDao.get(1); if(A != null && C != null){ boolean exists = false; // just check if it's updated or not for(AC a : a.getAC()){ if(a.getC().equals(c)){ // update field a.setExtra("extra updated"); exists = true; break; } } // add if(!exists){ ACId idAC = new ACId(); idAC.setA(a); idAC.setC(c); AC AC = new AC(); AC.setId(idAC); AC.setExtra("extra added"); a.getAC().add(AC); } ADao.save(A); }
źródło
Jak wspomniano wcześniej, w przypadku JPA, aby mieć szansę na dodatkowe kolumny, należy użyć dwóch skojarzeń OneToMany zamiast jednej relacji ManyToMany. Możesz także dodać kolumnę z wartościami generowanymi automatycznie; w ten sposób może działać jako klucz podstawowy tabeli, jeśli jest przydatny.
Na przykład kod implementacji dodatkowej klasy powinien wyglądać następująco:
@Entity @Table(name = "USER_SERVICES") public class UserService{ // example of auto-generated ID @Id @Column(name = "USER_SERVICES_ID", nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) private long userServiceID; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "USER_ID") private User user; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "SERVICE_ID") private Service service; // example of extra column @Column(name="VISIBILITY") private boolean visibility; public long getUserServiceID() { return userServiceID; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Service getService() { return service; } public void setService(Service service) { this.service = service; } public boolean getVisibility() { return visibility; } public void setVisibility(boolean visibility) { this.visibility = visibility; } }
źródło