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

これは、不要なクエリを避けるために、第 1 レベルのキャッシュ (場合によっては第 2 レベルのキャッシュも) を使用します。

于 2013-07-06T17:56:52.770 に答える