2017-06-22 77 views
1

可以说我有两个对象,一个是用户对象,另一个是状态对象。国家对象基本上是美国的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对象添加状态?

+0

在将它们添加到用户对象之前,如何检索状态对象? –

+0

@Aassass我为每个做了一个getStateById(),它将状态Object返回到数组列表中,然后使用setter方法将该数组列表添加到用户中 – Aria

+0

您可以提供处理保存方法的完整代码。为什么你的collection属性之上有一个@Column,你不需要这个,我想你有一个支持关系的表user_state? –

回答

1

此代码:

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

使用此配置,您应该能够从数据库获取状态,将其添加到新用户,然后保留它。我做了一个单元测试,它的工作原理!

+0

你是说要删除到@OneToMany配置? – Aria

+0

是的,因为你不需要它。您真正需要的是确保数据库中存在中间表“TBL_USERS_TBL_STATES”。 Hibernate将使用这个表来映射用户的状态(状态集合)! – rafaelim

+0

services_id?这个领域在哪里? – rafaelim

0

在你的情况下,可能会更好地使用manytomany协会与许多tomany hibernate不生成unicity约束。

对于onetoMany,Hibernate自动生成方案行为有点奇怪,但是您可以使用此解决方法。

试试这个:

@ManyToMany 
@JoinTable(name = "user_state") 
private List<State> states; 
+0

这不起作用,它不停地创建多个用户一次?如果我选择2个州,它会创建2个具有相同详细信息的用户(ID除外) – Aria

+0

它应该工作,也许您的保存逻辑不正确,请添加您的所有业务代码的发布详情,我需要整个图片。从用户实例化或加载直到持久化并刷新到数据库包含围绕adduser方法的代码。 –

相关问题