Java JPA持久化而不是更新

Java JPA持久化而不是更新,java,hibernate,jpa,Java,Hibernate,Jpa,我遇到了一个奇怪的问题,每当我试图在我的应用程序中编辑一个寄存器而不是更新实体的状态时,它都会保持一个新的状态。下面是我的update方法 public void update(Object obj) { EntityManagerFactory fac = Persistence.createEntityManagerFactory("crud"); EntityManager em = fac.createEntityManager(); em.merge(obj);

我遇到了一个奇怪的问题,每当我试图在我的应用程序中编辑一个寄存器而不是更新实体的状态时,它都会保持一个新的状态。下面是我的
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配置文件…然后可能是其中一个包含create值的标记。将其更改为“更新”。希望这对你有所帮助。。。首先像这样将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模式):


简单得多(是吗?:)Java可以非常简单和高效。我不确定您使用的是什么容器,但我建议您使用ApacheTomee。查看他们庞大的最新示例库。祝你好运

实际问题在JSF层

所有证据都表明,
editUserBean
属于请求范围。这意味着每个请求将获得一个新bean

因此,我们在每个请求上都使用一个新的
userToEdit
bean。它的属性将是
null
或原语的默认值(例如
int
long
0
),除非您在bean中明确声明了该属性的默认值。这包括
id
,在您的情况下是
0

合并bean时,持久化上下文中没有id为
0
的实体,数据库中也没有相应的条目,因此
merge
将持久化一个新实体。如果您正在为主键生成值,很可能您永远不会将
0
作为
id
,因此JPA层将保持新实体

解决此问题的一个简单方法是将用户信息存储在bean中,例如会话范围或用户定义的会话范围:

然后,您可以像往常一样注入bean,存储的
id
将在两次请求之间存活(不要忘记清理;正确划分会话边界和/或清理会话bean)


另一种解决方法——如果您必须将用户信息保留在请求范围内——是使用隐藏字段来保存
id
(以及您希望的任何不可编辑属性)的值。这样,用户
id
也将在下一次请求时提交,并且模型将正确更新

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


警告:虽然此解决方法非常流行,但仅当当前用户能够更新任何其他用户的信息时才执行此操作。为什么?恶意用户可以很容易地操纵DOM,以更改
用户.id
和/或提交包含任何
id
的虚假请求,从而滥用系统。

为什么要创建entityManager?每个实例应该创建一次(所有会话都在静态上下文中进行)。此外,您只需要持久化,而不是合并。EntityManager将映射已持久化的对象,并在向其添加新状态时对其进行更新。但是,如果每次要更新时都创建entityManager,它无法映射已持久化的对象。实际上,我将它放在那里是为了上下文的名称,我的entityManager是一个全局变量,因此您可以在静态{}块中创建它。调试并查看调用merge时对象是否具有id。您的表单中没有id字段,所以我猜提交时没有传递id。@AnthonyAccioly您的提示对我有用!问题是一旦提交,表单就会将id设置为0。正如预期的那样,id==0,它将一直存在。谢谢是的,试试看,可能每次创建EMF时都会擦除数据,确保配置文件中说的验证不创建。我认为这可能是问题,很好的建议,我的朋友如果它工作+1+0,我使用的是坚持。属性hibernate.hbm2ddl.auto设置为updateGoing以实现该功能。谢谢如果成功了,别忘了投票和/或接受我和其他人的答案;)这就是你奖励帮助你解决stackoverflow问题的人的方式:)哦,快!好吧,继续回来:)
@RequestScoped (or something)
public class EditUserBean {
   @Inject
   private MyServiceEJBThingy myServiceEJBThingy;


   public void update(Object obj) {
       // GUI logic here
       myServiceEJBThingy.update(obj);
   }
}
@ConversationScoped
class UserToEdit extends User {
   // ... or if you want, create a HAVE-A relationship
}
<h:inputHidden value="#{editUserBean.userToEdit.id}" />