Eliminar filas de la base de datos con EJB 3.0

Quiero eliminar una fila en una base de datos, así que creé un EJB que lo hace por mí.

@Stateless(name = "ejbs/AdminAcountEJB")
public class AdminAcountEJB implements IAdminAcountEJB  {

    @PersistenceContext
    private EntityManager entityManager;

    public void deleteRecord(Record record) {
                    entityManager.remove(record);
    }
}

No creé el objeto TransactionEntity y luego utilicé el método begin (), porque según entendí, los EJB ya están asegurados por transacciones.

Para ver si funciona en la interfaz de usuario (una página JSF 2.0), creé una tabla de datos con una columna con un enlace de comando de eliminación y la activé desde un bean de respaldo que está conectado al EJB:

página

<h:dataTable value="#{managementBB.retrieveRecords()}" var="record">
                   ...
                    <h:column>
    <h:commandLink value="X" action="#{managementBB.deleteRow(record)}"/>
                    </h:column>
</h:dataTable>

frijol de respaldo

 @Named("managementBB")
@SessionScoped
public class ManagementBB implements Serializable{

    @EJB
    private IAdminAcountEJB managementEJB;

    //...

    public String deleteRow(Record record) {

        managementEJB.deleteRecord(record);
        return "manage?faces-redirect=true;";
    }

Este es el error que veo en la consola cuando ciclking el enlace para eliminar una fila:

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception javax.faces.el.EvaluationException: javax.ejb.EJBException at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) at javax.faces.component.UICommand.broadcast(UICommand.java:315) at javax.faces.component.UIData.broadcast(UIData.java:912) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask.java:69) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309) at java.lang.Thread.run(Thread.java:662) Caused by: javax.ejb.EJBException at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:5119) at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5017) at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4805) at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2004) at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1955) at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:198) at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84) at $Proxy162.deleteRecord(Unknown Source) at backingbeans.ManagementBB.deleteRow(ManagementBB.java:46) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304) at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54) at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163) at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298) at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113) at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43) at backingbeans.ManagementBB_$$_javassist_132.deleteRow(ManagementBB_$$_javassist_132.java) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:737) at javax.el.BeanELResolver.invoke(BeanELResolver.java:467) at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:246) at com.sun.el.parser.AstValue.invoke(AstValue.java:228) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297) at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43) at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:72) at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:98) at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) ... 33 más Causado por: java.lang.IllegalArgumentException: La entidad debe ser administrada para llamar a remove: entity.Record@df8b3d, intente fusionar lo separado e intente eliminar nuevamente. en org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.performRemove (UnitOfWorkImpl.java:3539) en org.eclipse.persistence.internal.jpa.EntityManagerImpl.remove (EntityManagerImpl.java:435) en com.sun.enterprise.container .common.impl.EntityManagerWrapper.remove (EntityManagerWrapper.java:292) en ejbs.AdminAcountEJB.deleteRecord (AdminAcountEJB.java:23) en sun.reflect.NativeMethodAccessorImpl.invoke0 (método nativo) en sun.reflectAccess.Nativa .java: 39) en sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25) en java.lang.reflect.Method.invoke (Method.java:597) en org.glassfish.ejb.security.application.EJBSecurityManager. runMethod (EJBSecurityManager.java:1056) en org.glassfish.ejb.security.application.EJBSecurityManager.invoke (EJBSecurityManager.java:1128) en com.sun.ejb.containers.BaseContainer.invokeBeanMethod (BaseContainer.java:5292) .sun.ejb.EjbInvocation.invokeBeanMethod (EjbInvocation.java:615) en com.s un.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext (InterceptorManager.java:797) en com.sun.ejb.EjbInvocation.proceed (EjbInvocation.java:567) en org.jboss.weld.ejb.SessionBeanInterceptor.ar. java: 47) en sun.reflect.GeneratedMethodAccessor87.invoke (Fuente desconocida) en sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25) en java.lang.reflect.Method.invoke (Method.java:597) en .sun.ejb.containers.interceptors.AroundInvokeInterceptor.interceptor (InterceptorManager.java:858) en com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext (InterceptorManager.java:797) en com.sunedInvoke.Eproj (EjbInvocation.java:567) en com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround (SystemInterceptorProxy.java:157) en com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke (SystemInterceptor:139.java:86) en com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke (SystemInterceptor:25.java:597) sun.reflect.GeneratedMethodAccessor858.invoke (Fuente desconocida) en sun.refl ect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:797) en java.lang.reflect.Method.invoke (Method.java:367) en com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept (Interceptor:5264Manager.java en com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext (InterceptorManager.java:5252) en com.sun.ejb.containers.interceptors.InterceptorManager.intercept (InterceptorManager.java:190) en com.sun.ejb.containers .BaseContainer .__ intercepta (BaseContainer.java:XNUMX) en com.sun.ejb.containers.BaseContainer.intercept (BaseContainer.java:XNUMX) en com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke (EJBLocalObject.Invoke). ..

Como puede ver, uso CDI para beans (@Named) en lugar de @ManagedBeans, pero espero que esa no sea la razón. También me gustaría mencionar que en mi base de datos, tengo una tabla independiente, que no está relacionada en absoluto con la tabla Record, ¿podría afectar esto?

preguntado el 28 de agosto de 11 a las 02:08

1 Respuestas

La respuesta se puede encontrar en el stacktrace dentro de las líneas:

Causado por: java.lang.IllegalArgumentException: la entidad debe administrarse para llamar a remove: entity.Record@df8b3d, intente fusionar lo separado e intente eliminar nuevamente.

EntityManager.remove requiere que la referencia pasada como argumento sea una entidad gestionada, es decir, el objeto debe estar presente en el contexto de persistencia. Si está pasando una referencia de entidad desde un bean administrado por JSF o un bean administrado por CDI, sigue siendo una entidad no administrada / separada, a menos que haya obtenido originalmente la referencia de entidad del contexto de persistencia actual.

Para comprender esto mejor, debe conocer el ciclo de vida de la entidad JPA. En la mayoría de los casos, la entidad administrada que obtiene de un contexto de persistencia se separa al final de la transacción (es decir, cuando finaliza el contexto de persistencia). Por lo tanto, sus beans administrados JSF / CDI estarían trabajando con entidades separadas y no con entidades administradas. Cuando pasa la entidad separada de JSF de nuevo al EJB, invocando EntityManager.remove resultará en lo descrito IllegalArgumentException.

Por tanto, la solución es obtener la referencia a una entidad gestionada utilizando la entidad separada, utilizando EntityManager.merge (que fusiona el contenido de la entidad separada con el contexto de persistencia y devuelve una referencia a una entidad gestionada) o EntityManager.find (que devuelve una entidad gestionada del contexto de persistencia, si está presente allí). Yo prefiero usar EntityManager.find en el escenario donde es posible que la entidad separada sea modificada - cuando una entidad separada tiene relaciones con otras entidades, entonces el MERGE podría estar en cascada mientras el REMOVE Es posible que la operación no lo haga, si no tiene cuidado al definir qué operaciones deben conectarse en cascada.

Respondido 28 ago 11, 07:08

No estoy muy familiarizado con el ciclo de vida de JPA, pero después de leer la respuesta entendí cuál era el problema. Esto es lo que hice para solucionarlo: Record detachedRecord = entityManager.merge(record); entityManager.remove(detachedRecord); Funcionó perfectamente. ¡Muchos gracias! - javing

@sfrj, es posible que desee echar un vistazo al diagrama al final de esta página en la documentación de OpenJPA; ese es el ciclo de vida de la entidad JPA. - Vineet Reynolds

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.