Foros del Web » Programación para mayores de 30 ;) » Java »

Eliminar con Hibernate

Estas en el tema de Eliminar con Hibernate en el foro de Java en Foros del Web. Buenas tardes!! Espero que alguien pueda echarme una mano, porque no consigo encontrar la solución... Estoy intentando eliminar una fila de mi base de datos ...
  #1 (permalink)  
Antiguo 22/07/2008, 12:14
 
Fecha de Ingreso: marzo-2008
Mensajes: 19
Antigüedad: 16 años, 2 meses
Puntos: 0
Eliminar con Hibernate

Buenas tardes!!

Espero que alguien pueda echarme una mano, porque no consigo encontrar la solución...

Estoy intentando eliminar una fila de mi base de datos (MySql) con Hibernate, y resulta que este objeto tiene relaciones con otras tablas (claves foráneas).

Bien, el comportamiento que deseo es que si elimino por ejemplo, una empresa, se eliminen a su vez todo lo relacionado con ella, como clientes, presupuestos, proveedores... Para ello, he utilizado el atributo cascade="delete" en los <set>.

Al intentar eliminarlo me salta el siguiente error:

org.hibernate.PropertyValueException: not-null property references a null or transient value: es.proyecto.hibernate.mapeos.Empresa.usuarios

at org.hibernate.engine.Nullability.checkNullability( Nullability.java:72)

at org.hibernate.event.def.DefaultDeleteEventListener .deleteEntity(DefaultDeleteEventListener.java:173)

at org.hibernate.event.def.DefaultDeleteEventListener .onDelete(DefaultDeleteEventListener.java:110)

at org.hibernate.impl.SessionImpl.fireDelete(SessionI mpl.java:761)

at org.hibernate.impl.SessionImpl.delete(SessionImpl. java:739)

at es.proyecto.hibernate.dao.EmpresaDAO.eliminarEmpre sa(EmpresaDAO.java:191)

at es.proyecto.hibernate.bl.EmpresaBL.eliminarEmpresa (EmpresaBL.java:32)

at es.proyecto.struts.action.EmpresaAction.eliminarEm presa(EmpresaAction.java:229)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Native MethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(De legatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:585)

at org.apache.struts.actions.DispatchAction.dispatchM ethod(DispatchAction.java:274)

at org.apache.struts.actions.DispatchAction.execute(D ispatchAction.java:194)

at org.apache.struts.action.RequestProcessor.processA ctionPerform(RequestProcessor.java:419)

at org.apache.struts.action.RequestProcessor.process( RequestProcessor.java:224)

at org.apache.struts.action.ActionServlet.process(Act ionServlet.java:1194)

at org.apache.struts.action.ActionServlet.doGet(Actio nServlet.java:414)

at javax.servlet.http.HttpServlet.service(HttpServlet .java:690)

at javax.servlet.http.HttpServlet.service(HttpServlet .java:803)

at org.apache.catalina.core.ApplicationFilterChain.in ternalDoFilter(ApplicationFilterChain.java:269)

at org.apache.catalina.core.ApplicationFilterChain.do Filter(ApplicationFilterChain.java:188)

at org.apache.catalina.core.StandardWrapperValve.invo ke(StandardWrapperValve.java:210)

at org.apache.catalina.core.StandardContextValve.invo ke(StandardContextValve.java:174)

at org.apache.catalina.core.StandardHostValve.invoke( StandardHostValve.java:127)

at org.apache.catalina.valves.ErrorReportValve.invoke (ErrorReportValve.java:117)

at org.apache.catalina.core.StandardEngineValve.invok e(StandardEngineValve.java:108)

at org.apache.catalina.connector.CoyoteAdapter.servic e(CoyoteAdapter.java:151)

at org.apache.coyote.http11.Http11Processor.process(H ttp11Processor.java:870)

at org.apache.coyote.http11.Http11BaseProtocol$Http11 ConnectionHandler.processConnection(Http11BaseProt ocol.java:665)

at org.apache.tomcat.util.net.PoolTcpEndpoint.process Socket(PoolTcpEndpoint.java:528)

at org.apache.tomcat.util.net.LeaderFollowerWorkerThr ead.runIt(LeaderFollowerWorkerThread.java:81)

at org.apache.tomcat.util.threads.ThreadPool$ControlR unnable.run(ThreadPool.java:685)

at java.lang.Thread.run(Thread.java:595)




Me imagino que haya gente que si que haya podido realizar esta operación pues no me parece que sea nada extraño.

Muchas gracias

Un saludo
  #2 (permalink)  
Antiguo 22/07/2008, 14:12
Usuario no validado
 
Fecha de Ingreso: junio-2008
Mensajes: 386
Antigüedad: 15 años, 10 meses
Puntos: 10
Respuesta: Eliminar con Hibernate

Hola,

Verifica que antes del borrado no hayas hecho algun query a la base con la misma session de Hibernate, si es asi, cierra la session y posteriormente intenta hacer el borrado del objeto.

Tambien intenta ponerle a la etiqueta <set> los atributos cascade="persist,delete"

<set name="" table= "" cascade="persist,delete" inverse="true">

Intenta esto y ahi nos avisas.

saludos!
  #3 (permalink)  
Antiguo 23/07/2008, 07:58
Avatar de Llave  
Fecha de Ingreso: abril-2005
Ubicación: Galicia
Mensajes: 52
Antigüedad: 19 años
Puntos: 1
Respuesta: Eliminar con Hibernate

Del mensaje de error, deduzco que en la "cascada" de borrado intenta acceder a algún elemento que ya has borrado con anterioridad:

"org.hibernate.PropertyValueException: not-null property references a null or transient value: es.proyecto.hibernate.mapeos.Empresa.usuarios"

Esto se me ocurre que sea por dos motivos:
1.- O tienes la base de datos inconsistente (Lo cual es fácil si andas insertando y borrando sin transacciones).
2.- O alguna tabla tiene relación con otra tabla que tenga relacción con una tercera y a su vez esta se relaciones con la primera (en plan bucle cíclico).

Pero por experiencia propia yo miraría que no tengas entradas inconsistentes en la base de datos. Por que... supongamos que ordenas un borrado en cascada y el sistema falla en la mitad del borrado ¿Qué ocurre con lo que has borrado y lo que falta por borrar? ¿Controlas eso?
Es una suposición.

Espero que descubras por qué falla. Suerte!
  #4 (permalink)  
Antiguo 23/07/2008, 08:18
Avatar de djagu_26  
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 518
Antigüedad: 16 años, 3 meses
Puntos: 6
Respuesta: Eliminar con Hibernate

El problema es que no puedes eliminar ya que en tu caso usuarios deberia tener una empresa (id_empresa en la bd) me imagino y al eliminarla esa propiedad no puede ser null, esta claro que es un problema en el mapeo ya que no te funciona el eliminar en cascada, supongo que empresa tiene una lista de usuarios en el objeto empresa lo que tienes q hacer es recorrer con un for esa lista de usuarios e ir eliminando cada usuario antes de eliminar la empresa, asi con todo lo que tengas relacionado con empresa, una cosa OJO!!! con la eliminacion en cascada te pueedes llevar muy ingratas sopresas

saludos y cuidate
__________________
"La magia no existe, la programacion si"

A/P Agustin Sivoplas
[email protected]
  #5 (permalink)  
Antiguo 28/07/2008, 12:04
 
Fecha de Ingreso: marzo-2008
Mensajes: 19
Antigüedad: 16 años, 2 meses
Puntos: 0
Respuesta: Eliminar con Hibernate

Es al revés, los usuarios pueden tener empresas, es decir, es en la tabla empresa donde tengo una clave que hace referencia al usuario. Entonces, no sé cómo puedo solucionarlo porque el problema es que ese atributo no puede ser nulo.

Pero vamos, que me imagino que se pueda hacer de alguna forma, ¿no? Acepto sugerencias xD

Muchas gracias a todos

Un saludo
  #6 (permalink)  
Antiguo 28/07/2008, 17:37
Avatar de djagu_26  
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 518
Antigüedad: 16 años, 3 meses
Puntos: 6
Respuesta: Eliminar con Hibernate

Entonces 1 empresa solo puede tener 1 usuario? no seria una relacion n a n eso?
saludos
__________________
"La magia no existe, la programacion si"

A/P Agustin Sivoplas
[email protected]
  #7 (permalink)  
Antiguo 29/07/2008, 01:08
Avatar de Llave  
Fecha de Ingreso: abril-2005
Ubicación: Galicia
Mensajes: 52
Antigüedad: 19 años
Puntos: 1
Respuesta: Eliminar con Hibernate

A ver si lo he entendido.

Resumiendo... tienes dos entidades: Empresa y usuarios. Si mal no entendi, la relación entre estas dos entidades es N-1 Es decir, un usuario puede tener varias empresas.
Y la idea que tienes al borrar una empresa.. ¿es que esta elimine también al usuario?

Seguramente ahí esté tu problema. Deberías modificar tu esquema de borrado. Te pongo un ejemplo para que veas de lo que hablo.

Supongamos que en Usuarios tenemos 3 usuarios:
- Fulano
- Mengano
- Arrano

Y en Empresas, tenemos 10 empresas en plan:
- Empresa1
- Empresa2
- Empresa3
- ...
- Empresa10

De tal forma que las 8 primeras tienen enlace a Fulano.
Empresa9 a Mengano y Empresa10 a Arrano.

Según tu idea de borrado, empiezas a borrar empresas:

Borras la Empresa1, seguidamente te cargas al usuario Fulano.
---------------------------------
Aquí es donde veo el problema. En este mismo momento, tienes 7 empresas incosistentes en tu base de datos. Ya que Fulano ya no existe y hay 7 empresas que apuntan a donde antes estaba él (Empresa2,..., Empresa8). En el momento en que el sistema acceda al segundo elemento de la tabla empresas y quiera leer "Empresa2", verá que el enlace de usuario apunta a NULL ya que Fulano no existe y romperá.

Creo que es por este motivo que te falla. Corrígeme si no es así. fue lo que entendí leyendo tu post.

Puedes intentar borrar tú, las empresas del usuario a mano y seguidamente cargarte al usuario al final. O si no, ponerle el borrado en cascada al usuario y a partir de la empresa, accedes al usuario y ordenas borrar el usuario (ya se encargará Hibernate de borrar las empresas que lo tengan apuntado).

Espero que se solucione.
  #8 (permalink)  
Antiguo 29/07/2008, 05:09
 
Fecha de Ingreso: marzo-2008
Mensajes: 19
Antigüedad: 16 años, 2 meses
Puntos: 0
Respuesta: Eliminar con Hibernate

Sí, la relación es 1 a N, es decir, un usuario puede tener varias empresas, y cada empresa pertenece a un único usuario.

La idea de borrado es, borrar la empresa y todo lo relacionado con ella como presupuestos, proveedores, clientes, pero no el usuario, pues como bien apuntas, ese usuario puede tener otras empresas que no desea borrar.

Entonces, ¿cómo debo configurar empresa, usuarios y demás? Porque entonces creo que estoy poniendo el borrado en cascada en sitios que no me interesa.

Muchas gracias

Un saludo
  #9 (permalink)  
Antiguo 29/07/2008, 08:59
Avatar de Llave  
Fecha de Ingreso: abril-2005
Ubicación: Galicia
Mensajes: 52
Antigüedad: 19 años
Puntos: 1
Respuesta: Eliminar con Hibernate

A ver, yo te cuento como lo suelo hacer yo. A ver si te sirve de algo la información que yo te doy.

(Voy a hablar siempre en concepto de Bases de datos, no Hibernate).

Supongamos que tengo una entidad A que tiene relación 1-N con 2 entidades más, B y C.

A-----1-N------B
A-----1-N------C

Las referencias a A desde B y C son not-null.

Si yo deseo Borrar A, automáticamente, B y C es posible que tengan alguna referencia a NULL ya que apuntan a A y esta ha cambiado.

Creo que no se entiende bien. Pondré ejemplos más concretos.
A va a ser Usuarios.
B Empresas.
C Tareas.

Imaginemos que la situación es que Tenemos usuarios que tienen varias empresas y Pueden realizar diversas tareas con motivo de su formación profesional y tenemos registrado todo eso.
De forma que nuestra base de datos tiene 3 entidades USUARIOS, EMPRESAS, TAREAS.
Empresas y tareas tienen referencias a USUARIO, siendo estas Not null.

Código:
CREATE TABLE Usuarios (
id INT NOT NULL,
name VARCHAR(100),
PRIMARY KEY(id)
 );

CREATE TABLE Empresa (
id INT NOT NULL,
pertenece INT NOT NULL REFERENCES Usuarios(id) ON DELETE CASCADE,
PRIMARY KEY(id)
 );

CREATE TABLE Tareas (
id INT NOT NULL,
pertenece  INT NOT NULL REFERENCES Usuarios(id) ON DELETE CASCADE,
PRIMARY KEY(id)
 );
Si te fijas en el ejemplo. Si quiero mantener la consistencia de la base de datos. Debo poner un "On delete cascade" en los atributos que hacen referencia a otra clase. De esta forma, si borro un usuario que tenga empresas y tareas, la base de datos se encargará de buscar esas referencias y eliminar esas entradas de la base de datos también, quedando una base de datos consistente.

Pero... que pasaría si modificásemos la tabla Empresa y le quitásemos el cascade.
Código:
CREATE TABLE Empresa (
id INT NOT NULL,
pertenece INT NOT NULL REFERENCES Usuarios(id),
PRIMARY KEY(id)
 );
En el momento en que eliminemos un usuario, las tareas que tenga asociadas se borrarán automáticamente, no así las Empresas, quedandonos una base de datos inconsistente y erronea. En el momento en que acceda a las entradas de Empresa verá que alguna apunta a un usuario que no existe (NULL) violando la regla de definición de la tabla y rompiendo el sistema.

Espero que te resultase útil este ejemplo y puedas ver si cometiste algún error en tu Base de datos.
En principio... sólo necesitarías declarar los "Cascade" en tu BD. Hibernate ya los reconocería cuando la "mapees".

Suerte.
  #10 (permalink)  
Antiguo 29/07/2008, 14:05
 
Fecha de Ingreso: marzo-2008
Mensajes: 19
Antigüedad: 16 años, 2 meses
Puntos: 0
Respuesta: Eliminar con Hibernate

Antes de nada muchisimas gracias por tu explicación.

Ahora bien, sigo teniendo algunas dudas, y es que no entiendo, porque al intentar eliminar la empresa me da ese error de usuarios, pues no se está eliminando el usuario.

He puesto el delete cascade en la base de datos, pero hibernate no lo mapea :(

Te comento la configuración de Hibernate para estas clases a ver si me puedes ayudar:

Empresa.hbm.xml

<hibernate-mapping>
<class name="es.proyecto.hibernate.mapeos.Empresa" table="empresa" catalog="universidad">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="increment" />
</id>
<many-to-one name="usuarios" class="es.proyecto.hibernate.mapeos.Usuarios" fetch="select" cascade="delete">
<column name="email_usuario" length="45" not-null="true" />
</many-to-one>
<property name="nombre" type="java.lang.String">
<column name="nombre" length="45" not-null="true" />
</property>
<property name="cif" type="java.lang.String">
<column name="cif" length="25" not-null="true" />
</property>
<set name="presupuestoses" inverse="true" cascade="delete">
<key>
<column name="idEmp" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.Presupuestos" />
</set>
<set name="formaPagos" inverse="true" cascade="delete">
<key>
<column name="idEmp" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.FormaPago" />
</set>
<set name="pedidos" inverse="true" cascade="delete">
<key>
<column name="idEmp" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.Pedido" />
</set>
<set name="productos" inverse="true" cascade="delete">
<key>
<column name="emp" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.Producto" />
</set>
<set name="clientes" inverse="true" cascade="delete">
<key>
<column name="idEmpresa" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.Cliente" />
</set>
</class>
</hibernate-mapping>


Usuarios.hbm.xml

<hibernate-mapping>
<class name="es.proyecto.hibernate.mapeos.Usuarios" table="usuarios" catalog="universidad">
<id name="email" type="java.lang.String">
<column name="email" length="45" />
<generator class="assigned" />
</id>
<property name="contrasena" type="java.lang.String">
<column name="contrasena" length="6" not-null="true" />
</property>
<property name="nombre" type="java.lang.String">
<column name="nombre" length="25" not-null="true" />
</property>
<property name="apellidos" type="java.lang.String">
<column name="apellidos" length="45" not-null="true" />
</property>
<property name="fechanac" type="java.lang.String">
<column name="fechanac" length="15" not-null="true" />
</property>
<set name="empresas" inverse="true" cascade="delete">
<key>
<column name="email_usuario" length="45" not-null="true" />
</key>
<one-to-many class="es.proyecto.hibernate.mapeos.Empresa" />
</set>
</class>
</hibernate-mapping>

Comentar que para eliminar realizo una operación así:

sesion.delete(empresa);

¿No es posible con esta configuración que si se elimina una empresa se eliminen también los clientes, presupuestos,.. relacionados sin eliminar el usuario al que pertenece?

Muchas gracias

Un saludo
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 13:55.