17

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

<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";
    }

}

最后是 ActorDao:

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

}

如您所见,edit 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);
}

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

4

1 回答 1

41

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);
}

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

于 2013-07-06T17:56:52.770 回答