使用额外列映射多对多关联表
我的数据库包含3个表:用户和服务实体具有多对多的关系,并与SERVICE_USER表连接如下:
用户 – SERVICE_USER – 服务
SERVICE_USER表包含额外的BLOCKED列。
执行这种映射的最佳方法是什么? 这些是我的实体类
@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 }
我跟着这个例子http://giannigar.wordpress.com/2009/09/04/m … using-jpa /这是一些testing代码:
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);
问题是,Hibernate持久化User对象和UserService之一。 CmsService对象没有成功
我试图使用EAGER抓取 – 没有进展
是否有可能通过上面提供的映射来实现我期待的行为?
也许有一些更优雅的方式来映射多对多连接表与额外的列?
由于SERVICE_USER表不是纯粹的连接表,而是具有附加的function性字段(被阻止),所以必须将其映射为实体,并将用户和服务之间的多对多关联分解为两个OneToMany关联:一个用户有许多UserServices,一个服务有许多用户服务。
你没有向我们展示最重要的部分:映射和初始化你的实体之间的关系(即你有问题的部分)。 所以我会告诉你它应该是什么样子
如果你build立双向的关系,你应该有
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>(); }
如果你没有对你的关系进行任何级联,那么你必须坚持/保存所有的实体。 虽然只有关系的一方(这里是UserService方面)必须被初始化,但确保双方的连贯性也是一个很好的习惯。
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);
我search的方式来映射一个多对多的关联表与额外的列(S)与hibernateXML文件configuration。
假设有两个表“a”和“c”与多个到多个名为“extra”的列关联。 因为我没有find任何完整的例子,这里是我的代码。 希望它会帮助:)。
首先这里是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; } }
现在,我们必须创build关联表。 第一步是创build一个表示复杂主键(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; } }
现在让我们创build关联对象本身。
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(CC){ getId().setC(C); } public void setA(AA){ 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); } }
在这一点上,是时候用hibernate xmlconfiguration映射我们所有的类。
A.hbm.xml和C.hxml.xml(安静)。
<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_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>
这是要testing的代码示例。
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); }
如前所述,使用JPA,为了有机会获得额外的列,您需要使用两个OneToMany关联,而不是一个manyToMany关系。 您也可以添加一个自动生成值的列,以便它可以作为表的主键(如果有用的话)。
例如,额外类的实现代码应该如下所示:
@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; } }