如果我尝试删除它,为什么JPA就像我的实体一样是分离的,但如果我编辑它则不会​​分离?

时间:2013-07-06 13:44:26

标签: jsf jpa

所以我有一个基本的JSF Datatable,相关部分是:

<h:dataTable value="#{actorTableBackingBean.allActors}" var="actor">

    <h:column headerText="Actor Name" sortBy="#{actor.firstName}">
        <h:outputText value="#{actor.firstName}" />
    </h:column>

    <h:column>
        <h:form>
            <h:commandButton value="Delete Actor"
                             action="#{actorTableBackingBean.deleteActor(actor)}"/>
        </h:form>
    </h:column>

    <h:column>
        <h:form>
            <h:commandButton value="Randomize Actor Name"
                             action="#{actorTableBackingBean.editActor(actor)}"/>
        </h:form>
    </h:column>

</h:dataTable>

这就是ActorTableBackingBean的样子:

@Named
@RequestScoped
public class ActorTableBackingBean implements Serializable {

    @Inject
    ActorDao actorDao;

    private List<Actor> allActors;

    public List<Actor> getAllActors() {
        return allActors;
    }

    @PostConstruct
    public void fillUp(){
        allActors = actorDao.getAllT();
    }

    public String deleteActor(Actor a){
        removeActor(a);
        return "/allActors.xhtml";
    }

    private String removeActor(Actor a){
        try{
            actorDao.deleteActor(a);
            return null;
        }catch (Exception e){
            return null;
        }
    }

    public String editActor(Actor actor){
        actor.setFirstName("SomeRandonName");
        actorDao.editActor(actor);
        return "/allActors.xhtml";
    }

}

最后是演员道:

@Stateless
public class ActorDao extends GeneralDao<Actor> implements Serializable {

    @Override
    protected Class<Actor> getClassType() {
        return Actor.class;
    }

    @Override
    public Actor getWithId(int id){
        TypedQuery<Actor> typedQuery =
                em.createQuery("Select a From Actor a WHERE a.actorId =" + id,Actor.class);
        return typedQuery.getSingleResult();
    }

    public void editActor(Actor a){
        em.merge(a);
    }

    public void deleteActor(Actor a){
        em.remove(a);
    }

}

因此,您可以看到编辑Actor调用 em.merge(a),这样就可以了。 但是 em.remove(a)将返回:

Caused by: java.lang.IllegalArgumentException: Entity must be managed to call remove: com.tugay.sakkillaa.model.Actor@6ae667f, try merging the detached and try the remove again.

即使我尝试:

 public void deleteActor(Actor a){
    em.merge(a); 
    em.remove(a);
 }

我仍然得到同样的例外。

那么如何编辑行,而不是删除它?

我唯一能让它发挥作用的方式是:

public void deleteActor(Actor a){
    Actor actorToBeRemoved = getWithId(a.getActorId());
    em.remove(actorToBeRemoved);
}

我做错了什么,或者无法理解?

1 个答案:

答案 0 :(得分:40)

merge()方法执行以下操作:它接受一个分离的实体,从数据库加载具有相同ID的附加实体,将分离的实体的状态复制到附加的实体,并返回附加的实体。正如您在本说明中所述,分离的实体根本不会被修改,也不会附加。这就是你得到例外的原因。

如果你这样做,你就不会得到它

public void deleteActor(Actor a){
    a = em.merge(a); // merge and assign a to the attached entity 
    em.remove(a); // remove the attached entity
}

也就是说,合并是完全没必要的,因为您要做的就是删除实体。最后一个解决方案很好,除了它真正从数据库加载实体,这也是不必要的。你应该简单地做

public void deleteActor(Actor a){
    Actor actorToBeRemoved = em.getReference(Actor.class, a.getActorId());
    em.remove(actorToBeRemoved);
}

请注意,您的getWithId()方法效率不高,而且不必要复杂。你应该用

替换它
public Actor getWithId(int id){
    return em.find(Actor.class, id);
}

将使用第一级缓存(也可能是第二级缓存)以避免不必要的查询。