在不创建新对象的情况下将对象 A 中的对象添加到对象 B 中?休眠

Adding an object from Object A into Object B without creating new object ? HIBERNATE

假设我有两个对象,一个是用户对象,另一个是状态对象。 state 对象基本上是美国的 50 个州,所以它永远不需要改变。然而,用户对象有一个用户去过的国家的集合。所以像这样:

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

States 实体如下所示:

@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 似乎做同样的事情,其余的我认为我不需要 (删除、分离等)。我的问题是: 如何在不出现该错误的情况下向用户对象添加状态?

在您的情况下,最好使用多对多关联与多对多休眠不生成单一性约束。

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

试试这个:

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

此代码有效:

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 个 table,如下所示: TBL_USERS、TBL_STATES 和 TBL_USERS_TBL_STATES

TBL_USERS_TBL_STATES table 是 Hibernate 在使用 @ManyToMany 注释 属性 时使用的默认 table 名称。如果要更改 TBL_USERS_TBL_STATES 的 tablename,也请使用 @JoinTable 注释。请参阅文档 here

使用此配置,您应该能够从数据库中获取状态,将其添加到新用户,然后保存它。我进行了单元测试并且它有效!