使用额外的列映射多对多关联表

我的数据库包含3个表: 用户和服务实体具有多对多的关系,并与 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... 使用-jpa/ 下面是一些测试代码:

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 提取-没有进展

有没有可能通过上面提供的映射实现我期望的行为?

也许有一些更优雅的方法来映射多个到多个带有附加列的连接表?

126812 次浏览

由于 SERVICE _ USER 表不是一个纯粹的连接表,而是具有附加的功能字段(阻塞) ,因此必须将其映射为一个实体,并将 User 和 SERVICE 之间的多对多关联分解为两个 OneTomany 关联: 一个 User 具有许多 UserServices,而一个 SERVICE 具有许多 UserServices。

您还没有向我们展示最重要的部分: 实体之间关系的映射和初始化(也就是您遇到问题的部分)。所以我会告诉你它应该是什么样子的。

如果将关系设置为双向的,那么应该

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);

我搜索一种方法来映射一个多对多关联表,其中包含额外的列,并在 xml 文件配置中使用 hibernate。

假设有两个表‘ a’和‘ c’,其中多对多关联与一个名为‘ tra’的列关联。因为我没有找到任何完整的例子,这里是我的代码。希望能有所帮助:)。

首先是 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;
}


}

现在,我们必须创建关联表。第一步是创建一个表示复杂主键(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;
}
}

现在让我们创建关联对象本身。

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);
}
}

此时,应该使用 hibernate 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>

下面是要测试的代码示例。

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;
}


}