Mapowanie tabeli asocjacji wielu do wielu z dodatkową kolumną)
Moja baza danych zawiera 3 tabele: Jednostki User I Service mają relację many-to-many i są połączone z tabelą SERVICE_USER w następujący sposób:
USERS-SERVICE_USER-SERVICES
Tabela SERVICE_USER zawiera dodatkową blokowaną kolumnę.
Jaki jest najlepszy sposób na wykonanie takiego mapowania? To są moje klasy encji
@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
}
Podążyłem za tym przykładem http://giannigar.wordpress.com/2009/09/04/m ... używanie-jpa/ Oto kilka testów kod:
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 hibernate utrzymuje User object i userservice one. Brak sukcesu z obiektem CmsService
Próbowałem użyć EAGER fetch-bez postępu
Czy możliwe jest osiągnięcie takiego zachowania, jakiego oczekuję dzięki mapowaniu podanemu powyżej?
Może jest jakiś bardziej elegancki sposób mapowania wielu do wielu tabel z dodatkową kolumną?
3 answers
Ponieważ tabela SERVICE_USER nie jest czystą tabelą przyłączenia, ale ma dodatkowe pola funkcyjne (zablokowane), musisz mapować ją jako encję i rozkładać wiele do wielu skojarzeń między Użytkownikiem a usługą na dwa onetomany skojarzenia : jeden użytkownik ma wiele UserServices, a jedna usługa ma wiele UserServices.
Nie pokazałeś nam najważniejszej części: mapowania i inicjalizacji relacji między twoimi podmiotami (tj. części, z którą masz problemy). Więc pokażę jak to powinno wyglądać.
Jeśli tworzysz relacje dwukierunkowe, powinieneś więc mieć
class User {
@OneToMany(mappedBy = "user")
private Set<UserService> userServices = new HashSet<UserService>();
}
class UserService {
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "service_code")
private Service service;
@Column(name = "blocked")
private boolean blocked;
}
class Service {
@OneToMany(mappedBy = "service")
private Set<UserService> userServices = new HashSet<UserService>();
}
Jeśli nie umieścisz kaskady na swoich relacjach, musisz utrzymywać / zapisywać wszystkie byty. Chociaż tylko strona posiadająca relację (tutaj Strona UserService) musi zostać zainicjowana, dobrą praktyką jest również upewnienie się, że obie strony są spójne.
User user = new User();
Service service = new Service();
UserService userService = new UserService();
user.addUserService(userService);
userService.setUser(user);
service.addUserService(userService);
userService.setService(service);
session.save(user);
session.save(service);
session.save(userService);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 12:05:27
Szukam sposobu na mapowanie tabeli asocjacji wielu do wielu z dodatkowymi kolumnami z hibernate w konfiguracji plików xml.
Zakładając, że z mają dwie tabele ' a 'i' c 'z powiązaniem wielu 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 Javy.
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 asocjacyjny.
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 za pomocą konfiguracji hibernate xml.
A. hbm.xml i C. hxml.xml (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>
A następnie plik mapowania asocjacji, 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 próbka kodu 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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 16:34:39
Jak wspomniano wcześniej, w przypadku JPA, aby mieć szansę na dodatkowe kolumny, musisz użyć dwóch skojarzeń OneToMany, zamiast jednej relacji Wielotomany. Można również dodać kolumnę z wartościami autogenerowanymi; w ten sposób może ona działać jako klucz podstawowy tabeli, jeśli jest to użyteczne.
Na przykład kod implementacji dodatkowej klasy powinien wyglądać tak:
@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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 22:29:10