在persist()之后但在flush()之前更改JPA实体不起作用

时间:2012-10-08 20:15:20

标签: java hibernate jpa jpa-2.0

我正在使用带有Hibernate ver的JPA 2。 4.1.7.Final作为JPA实现。我也使用Spring框架v.3.1.2.RELEASE来清楚。这是我的问题。

我写了一个方法来添加/更新我的用户实体。

@Override
@Transactional
public void saveUser(UserForm userForm) {
    User user;

    if (userForm.getId() == null) { // new user
        user = new User();
        user.setCreationDate(new Date());
        entityManager.persist(user); // !!!
    } else {
        user = entityManager.find(User.class, userForm.getId());
    }

    user.setFirstName(userForm.getFirstName());
    user.setLastName(userForm.getLastName());
    user.setMiddleName(userForm.getMiddleName());

    user.setEmail(userForm.getEmail());

    user.setRole(entityManager.find(Role.class, 1));//TODO

    user.setLogin(userForm.getLogin());
    user.setPassword(userForm.getPassword1());

    entityManager.flush();
}

我正在测试用户的添加(userForm.getId()== null)。上面的代码不起作用,给出错误:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Column 'first_name' cannot be null
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:989)
...

但是。如果我将来自persist()的调用移到flush()之前的结尾,一切正常:

@Override
@Transactional
public void saveUser(UserForm userForm) {
    User user;

    if (userForm.getId() == null) { // new user
        user = new User();
        user.setCreationDate(new Date());
    } else {
        user = entityManager.find(User.class, userForm.getId());
    }

    user.setFirstName(userForm.getFirstName());
    user.setLastName(userForm.getLastName());
    user.setMiddleName(userForm.getMiddleName());

    user.setEmail(userForm.getEmail());

    user.setRole(entityManager.find(Role.class, 1));//TODO

    user.setLogin(userForm.getLogin());
    user.setPassword(userForm.getPassword1());

    entityManager.persist(user);// !!!
    entityManager.flush();
}

我认为发生的事情是在第一个(问题)情况下它尝试存储在持久调用时存在的User对象数据,尽管在flush()期间执行了实际的保存( upd。错误。它试图在persist()调用时发出sql insert。是什么让我想到这种方式是当我尝试调试时我发现它仍然试图在内部的某处插入正确的creation_date,但其他值为空。

但是我发誓,在我几年前一直在努力的其他项目中,这个工作得很好,不过我使用的是Oracle而不是MySQL(我认为这不是原因)和旧版本的框架。

这可能是什么问题?也许Hibernate有一些配置选项影响这个?

或者这是正确的行为以及我对JPA API的误解?

UPD。我正在使用

@Id
@GeneratedValue
@Column(columnDefinition="INT")
private int id;

用于用户entiry中的id字段。我相信这意味着生成策略= AUTO,这适用于mysql auto_increment key。

2 个答案:

答案 0 :(得分:1)

您将用户名设置为null(user.setFirstName(userForm.getFirstName());),因为userForm.getFirstName()返回null,并且您的错误显示为:Column 'first_name' cannot be null

您应该检查为什么userForm.getFirstName()返回null或允许用户的名字为null,因为您当前的实体配置不允许这样做。

也许您可以向我们展示用户实体?

答案 1 :(得分:1)

这是正确的行为。在第一次调用persist()时,用户的firstName为null。你已经在这一点之后设置了第一个名字,但在刷新之前,JPA / Hibernate准备好的命令就像是,

在持久化时,用户对象的状态可以说是user @ version1 从user @ version1对象

插入用户值(id,creationdate,null,null ..)

现在新用户版本存在user @ version2

在冲洗时,

检查是否有任何挂起的插入/更新..将所有对象带到版本1,这是在上次持续时。

请注意,flush可能会也可能不会在DB中进行物理插入操作,但是对象会被带到正确的状态,这意味着非持久性更改将会丢失。

不要担心,如果它在使用hibernate 3之前工作正常,并且在迁移到hibernate 4时开始不工作。我有几个问题,其中hibernate 3没有问题,但在没有额外修复的情况下无法在hibernate 4上运行。