So I have a basic JSF Datatable, the relavent part is:
<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>
And this is what ActorTableBackingBean looks like:
@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";
}
}
And finally 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);
}
}
So as you can see edit Actor calls em.merge(a) and this works just fine. However em.remove(a) will return:
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.
Even if I try:
public void deleteActor(Actor a){
em.merge(a);
em.remove(a);
}
I am still getting the same exception.
So how it works for editing the row, but not for deleting it?
Only way I could make it work was:
public void deleteActor(Actor a){
Actor actorToBeRemoved = getWithId(a.getActorId());
em.remove(actorToBeRemoved);
}
What is it that I am doing wrong, or not able to understand?
The merge() method does the following: it takes a detached entity, loads the attached entity with the same ID from the database, copies the state of the detached entity to the attached one, and returns the attached entity. As you note in this description, the detached entity is not modified at all, and doesn't become attached. This is why you get the exception.
You wouldn't get it if you did
public void deleteActor(Actor a){
a = em.merge(a); // merge and assign a to the attached entity
em.remove(a); // remove the attached entity
}
That said, merging is completely unnecessary, since all you want to do is remove the entity. The last solution is fine, except it really loads the entity from the database, which is also unnecessary. You should simply do
public void deleteActor(Actor a){
Actor actorToBeRemoved = em.getReference(Actor.class, a.getActorId());
em.remove(actorToBeRemoved);
}
Note that your getWithId()
method is not efficient, and needlessly complex. You should replace it with
public Actor getWithId(int id){
return em.find(Actor.class, id);
}
which will use the first-level cache (and potentially the second-level one as well) to avoid unnecessary queries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With