JPA持久而不是更新

时间:2014-02-17 19:37:19

标签: java hibernate jpa

我遇到了一个奇怪的问题,每当我尝试在我的应用程序中编辑寄存器而不是更新实体的状态时,它会持续存在一个新的。这是我的update方法

public void update(Object obj) {
    EntityManagerFactory fac = Persistence.createEntityManagerFactory("crud");
    EntityManager em = fac.createEntityManager();
    em.merge(obj);
    em.getTransaction().begin();
    em.getTransaction().commit();
    em.close();
    fac.close();
}

我的猜测是当我提交编辑表单并且调用setter时Id以某种方式设置为0.这可能发生吗?表格如下:

<h:form>
                <p:panelGrid columns="2" style="margin: 0 auto;">
                    <f:facet name="header">
                        Edit form
                    </f:facet>
                    Name:
                    <h:inputText id="nome" value="#{editUserBean.userToEdit.name}"/>
                    Age:
                    <h:inputText value="#{editUserBean.userToEdit.age}" converter="javax.faces.Integer"/>
                    Pass:
                    <h:inputText value="#{editUserBean.userToEdit.password}"/>
                    Gender:
                    <h:selectOneRadio value="#{editUserBean.userToEdit.gender}" style="font-size: 12px;">
                        <f:selectItem itemValue="Masc" itemLabel="Masc" />
                        <f:selectItem itemValue="Fem" itemLabel="Fem" />
                    </h:selectOneRadio>
                    <f:facet name="footer">
                        <div align="center">
                            <h:commandButton value="save" actionListener="#{editUserBean.save}" icon="ui-icon-check"/>
                        </div>
                    </f:facet>
                </p:panelGrid>
</h:form>

Hibernate正在查询:

Hibernate: 
    select
        hibernate_sequence.nextval 
    from
        dual
Hibernate: 
    insert 
    into
        users
        (age, gender, name, password, id) 
    values
        (?, ?, ?, ?, ?)

3 个答案:

答案 0 :(得分:1)

我不知道你是否已经尝试了这个但是检查了hibernate配置文件...然后可能是包含值create的标签之一。将其更改为更新。希望这有帮助

答案 1 :(得分:1)

一些事情......首先将这样的PersistenceContext注入您的EJB:

@PersistenceContext
private EntityManager em;

接下来,使用正确的自动事务处理标记您的函数或整个EJB:

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MyServiceEJBThingy {
    @PersistenceContext
    private EntityManager em;

在您的方法中,除了您的业务逻辑之外,不要做任何事情。交易信息现在可以自动处理:

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MyServiceEJBThingy {
    @PersistenceContext
    private EntityManager em;

    public void update(Object obj) {
        //GUI independent business logic here
        em.merge(obj);
    }
}

最后,现在将您的EJB注入视图控制器中(假设您正在使用MVVM模式):

@RequestScoped (or something)
public class EditUserBean {
   @Inject
   private MyServiceEJBThingy myServiceEJBThingy;


   public void update(Object obj) {
       // GUI logic here
       myServiceEJBThingy.update(obj);
   }
}

更简单的是吗? :) Java可以非常简单和高效。我不确定你正在使用什么容器,但我建议使用Apache TomEE。查看他们庞大的最新示例库here。祝你好运!!!

答案 2 :(得分:1)

实际问题出在JSF层。

所有证据都指出editUserBean 请求作用域。这意味着每个请求都会获得一个新bean。

因此,我们正在为每个请求使用 userToEdit bean。它的属性可以是null或基元的默认值(例如0 intlong),除非你明确声明了属性内的属性的默认值。豆。这包括id,在您的情况下为0

合并bean时,持久化上下文中没有标识为0的实体或数据库中的相应条目,因此merge将保留新实体。如果要为主键生成值,则可能永远不会将0作为id,因此JPA层将保持新实体的持久性。

针对此问题的一个简单修复方法是将用户信息存储在具有broader scope的bean中,例如会话范围或用户定义的会话范围:< / p>

@ConversationScoped
class UserToEdit extends User {
   // ... or if you want, create a HAVE-A relationship
}

然后你可以照常注入你的bean,并且存储的id将在请求之间存活(不要忘记清理;正确划分对话边界和/或清理会话bean)。


另一种解决方法 - 如果您绝对必须将用户信息保留在请求范围中 - 使用隐藏字段来保存id的值(以及任何不可编辑的值)你希望的财产)。这样,用户id也将在下一个请求时提交,模型将正确更新。

<h:inputHidden value="#{editUserBean.userToEdit.id}" />

警告:虽然此解决方法非常受欢迎,但只有在当前用户能够更新任何其他用户的信息时才能执行此操作。为什么?恶意用户可以轻松操纵DOM,以便更改user.id和/或提交包含任何id的虚假请求以滥用系统。