将对象A中的对象添加到对象B中而不创建新对象? HIBERNATE
可以说我有两个对象,一个是用户对象,另一个是状态对象。国家对象基本上是美国的50个州,所以它不必改变。然而,用户对象具有用户所在的国家集合。所以像这样的:将对象A中的对象添加到对象B中而不创建新对象? HIBERNATE
@Entity
@Table(name="tbl_users")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id", unique=true, nullable = false)
private int id;
@Column(name="user_name")
private String name;
@OneToMany(targetEntity=State.class, orphanRemoval = false)
@Column(name="states")
private Collection<State> states;
//getters and setters
}
和美国实体看起来是这样的:
@Entity
@Table(name="tbl_states")
class State {
@Id
@Column(name="id", unique=true, nullable=false)
private int id;
@Column(name="state")
private String state;
// getters and setters
}
代码添加用户(使用Hibernate):
public int addUser(User user) {
em.persist(user);
em.flush();
return user.getId();
}
代码通过ID获取状态:
public State getStateById(int id) {
return em.createQuery("SELECT s FROM State s WHERE s.id =:id, State.class)
.setParameter("id", id)
.getSingleResult();
}
但是当我尝试创建一个用户,并选择几个州,我得到一个PSQLException:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_g6pr701i2pcq7400xrlb0hns"
2017-06-21T22:54:35.959991+00:00 app[web.1]: Detail: Key (states_id)=(5) already exists.
我试图寻找了级联方法,看看我是否可以使用任意的,但Cascade.MERGE和Cascade.PERSIST似乎做同样的事情,其余的我不认为我需要(REMOVE,DETACH等)。我的问题是: 如何在没有该错误的情况下向User对象添加状态?
此代码:
class Example {
@Test
public void workingTest() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU");
EntityManager em = emf.createEntityManager();
// Creating three states
State alabama = new State(state: 'Alabama');
State louisiana = new State(state: 'Louisiana');
State texas = new State(state: 'Texas');
em.getTransaction().begin();
em.persist(alabama);
em.persist(louisiana);
em.persist(texas);
em.getTransaction().commit();
List<State> states = em.createQuery('FROM State').getResultList();
// Assert only three states on DB
assert states.size() == 3;
User userFromAlabama = new User();
User userFromAlabamaAndTexas = new User();
em.getTransaction().begin();
State alabamaFromDB = em.find(State, alabama.getId());
State texasFromDB = em.find(State, texas.getId());
userFromAlabama.getStates().add(alabamaFromDB);
userFromAlabamaAndTexas.getStates().add(alabamaFromDB);
userFromAlabamaAndTexas.getStates().add(texasFromDB);
em.persist(userFromAlabama);
em.persist(userFromAlabamaAndTexas);
em.getTransaction().commit();
states = em.createQuery('FROM State').getResultList();
// Assert only three states on DB again
assert states.size() == 3;
// Assert one user
User userFromDB = em.find(User, userFromAlabama.getId());
assert userFromDB.getStates().size() == 1;
userFromDB = em.find(User, userFromAlabamaAndTexas.getId());
assert userFromDB.getStates().size() == 2;
}
}
@Entity
@Table(name="tbl_users")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id
@Column(name="user_name")
private String name
@ManyToMany
private Collection<State> states = Lists.newArrayList()
// Getters and setters
}
@Entity
@Table(name="tbl_states")
class State {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="state")
private String state;
// Getters and setters
}
你应该改变你的映射@ManyToMany!
而且你必须对DB 3个表是这样的: TBL_USERS,TBL_STATES和TBL_USERS_TBL_STATES
的TBL_USERS_TBL_STATES表是当一个属性与@ManyToMany注解是Hibernate使用默认的表名。如果要更改TBL_USERS_TBL_STATES的表名,也可以使用@JoinTable注释。请参阅文档here
使用此配置,您应该能够从数据库获取状态,将其添加到新用户,然后保留它。我做了一个单元测试,它的工作原理!
在你的情况下,可能会更好地使用manytomany协会与许多tomany hibernate不生成unicity约束。
对于onetoMany,Hibernate自动生成方案行为有点奇怪,但是您可以使用此解决方法。
试试这个:
@ManyToMany
@JoinTable(name = "user_state")
private List<State> states;
这不起作用,它不停地创建多个用户一次?如果我选择2个州,它会创建2个具有相同详细信息的用户(ID除外) – Aria
它应该工作,也许您的保存逻辑不正确,请添加您的所有业务代码的发布详情,我需要整个图片。从用户实例化或加载直到持久化并刷新到数据库包含围绕adduser方法的代码。 –
在将它们添加到用户对象之前,如何检索状态对象? –
@Aassass我为每个做了一个getStateById(),它将状态Object返回到数组列表中,然后使用setter方法将该数组列表添加到用户中 – Aria
您可以提供处理保存方法的完整代码。为什么你的collection属性之上有一个@Column,你不需要这个,我想你有一个支持关系的表user_state? –