Integrity constraint violation

210 views
Skip to first unread message

Felix

unread,
Aug 5, 2013, 9:33:08 AM8/5/13
to symfo...@googlegroups.com
Al intentar eliminar un registro que tiene registros hijos me sale el siguiente error:

An exception occurred while executing 'DELETE FROM Tipo WHERE id = ?' with params [1]:

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`my`.`concepto`, CONSTRAINT `FK_9DF5EA869EEEC2ED` FOREIGN KEY (`tipo_id`) REFERENCES `tipo` (`id`))

Es correcto el error, pero quiero mostrar un mensaje mas bonito, por ejemplo "No se puede eliminar porque tiene registros relacionados".
Esta es la función en el controlador.

    public function deleteAction(Request $request, $id)
    {
        $form = $this->createDeleteForm($id);
        $form->bind($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $entity = $em->getRepository('MyBundle:Tipo')->find($id);

            if (!$entity) {
                throw $this->createNotFoundException('Unable to find Tipo entity.');
            }

            $em->remove($entity);
            $em->flush();
        }

        return $this->redirect($this->generateUrl('tipo'));
    }

aprendizenlared

unread,
Aug 5, 2013, 10:01:15 AM8/5/13
to symfo...@googlegroups.com
Pero ese error es una excepción en el momento de hacer el remove. Lo normal creo yo sería en el momento de realizar el borrado comprobar si tiene hijos hacer lo que queiras, lanzar una excepción con el mensaje que quieras, crear un mensaje flash, etc...

Felix

unread,
Aug 5, 2013, 10:24:59 AM8/5/13
to symfo...@googlegroups.com
No hay por qué realizar el trabajo de la base de datos, puedo capturar el error de la base de datos y mostrar el mensaje. Es lo que hago siempre en aplicaciones de escritorio, pero aquí estoy perdido. Traté de capturar el error pero explotó sin pasar por el catch.

            $em->remove($entity);
            try {
                $em->flush();
            } catch (\PDOException $e) {
                $form->addError(new FormError("No se puede eliminar porque tiene registros relacionados."));
                //$this->get('session')->setFlash('errordelete', "No se puede eliminar porque tiene registros relacionados.");
                return $this->redirect($this->getRequest()->getRequestUri());
            }

aprendizenlared

unread,
Aug 5, 2013, 11:15:32 AM8/5/13
to symfo...@googlegroups.com
Personalmente aunque lo haya hecho alguna vez no me gusta eso de capturar excepciones pudiendo controlarlo de otra manera... creo recordar que cuando estudiaba programación me decian que en una división es mejor comprobar que el divisor no es 0 antes de crear una excepción para ello. 
Y en aplicaciones de escritorio cuando programe en visual studio que que lo desaconsejaban por tema de rendimiento.

En un principio creo recordar que ami eso me funcionaba pero no tengo el código para comprobarlo. Seguro que no pasa por el catch no?? que a mí alguna vez me ha pasado que tambien se creaba una excepcion en el catch casi siempre porque al hacer copia y pega se me olvidaba incluir algun use :) por ejemplo en tu caso seguro que se me olvidaba poner use ...../FormError jeje

Pero bueno otra cosa que no me gusta de la excepción es porque imagínate que el error es causado a otra cosa diferente a que existan registros relacionados. Base de datos bloqueada, recurso no existente... etc. 

Felix

unread,
Aug 5, 2013, 12:09:10 PM8/5/13
to symfo...@googlegroups.com
No pasa por el catch, comenté todo el código dentro de él, puse un 'echo' y nada. Así que no es algo que se me olvidó incluir, al menos por ahora.
En cuanto a la captura de error, no pensaba capturar todas, solo iba a capturar el número que me interesaba y relanzar las restantes, después averiguaré como se hace esto último pero vamos paso a paso.

En Visual Basic 6, que es donde hago las aplicaciones de escritorio, es mucho mas lento buscar los registros dependientes que capturar la excepción, en Symfony no tengo idea. Estoy aprendiendo.
Tampoco tengo idea de como buscar los registros relacionados en Symfony, Si la búsqueda es a mano, realizando consultas a la base de datos uno mismo, entonces la variante de la excepción me parece mejor, se me puede olvidar alguna relación o se puede agregar una relación nueva mas tarde y olvidarme de actualizar el código.

No se por qué en la documentación de Symfony no hay un ejemplo de esto, me imagino que un requerimiento muy común. No encontré ejemplos buscando en Google tampoco.

¿Puedes ponerme el código de lo que haces para esto?

aprendizenlared

unread,
Aug 5, 2013, 4:05:14 PM8/5/13
to symfo...@googlegroups.com
Bueno ya te comento que yo hablo desde mi ignorancia que es bastante grande :) Pues hasta donde yo se si tienes dos entidades por ejemplo Equipo y Jugadores.

Tendras una propiedad en Equipo que sea jugadores y será una relación OneToMany (o ManyToOne, que nunca me acuerdo correctamente de los lados ya que casi siempre copio y pego jeje) por lo tanto puedes crear un método equipo que sea hasJugadores y ahí simplemente mirar si count($this->jugadores) -creo que era- es mayor que 0.  así si tienes la entidad solo tienes que llamar a esté método. Por lo que recuerdo del libro de javier eguiluz esta llamada a jugadores de por si no existe, doctrine se encargará de buscarlas en la base de datos, para mejorar el rendimiento lo mejor sería en el repositorio crear un find que te devuelva un join entre equipo y jugadores, y así solo realizas una acción en la base de datos. Pero bueno, yo creo recordar que lo hago así. 

Espero que algo te valga :)

Marcelo Prizmic

unread,
Aug 6, 2013, 9:03:40 AM8/6/13
to symfo...@googlegroups.com
En este caso querés que se borre o no? con CASCADE te borraría y no te
tiraría error.

Tal vez se pueda manejar con niveles de aviso de error

Marcelo
> --
> --
> Has recibido este mensaje porque estás suscrito al grupo "symfony-es" de
> Google Groups.
> Para publicar en este grupo, envía un email a symfo...@googlegroups.com
> Para darte de baja, envía un email a symfony-es+...@googlegroups.com
> El resto de opciones puedes encontrarlas en
> http://groups.google.com/group/symfony-es?hl=es
>
> ---
> Has recibido este mensaje porque estás suscrito al grupo "symfony-es" de
> Grupos de Google.
> Para anular la suscripción a este grupo y dejar de recibir sus correos
> electrónicos, envía un correo electrónico a
> symfony-es+...@googlegroups.com.
> Para obtener más opciones, visita https://groups.google.com/groups/opt_out.
>
>

Felix

unread,
Aug 6, 2013, 9:52:09 AM8/6/13
to symfo...@googlegroups.com
No quiero que se borre. Solo mostrar un mensaje diciendo que no se puede borrar.

Marcelo Prizmic

unread,
Aug 6, 2013, 12:34:18 PM8/6/13
to symfo...@googlegroups.com
ok. Entonces haría alguno de los chequeos que te comentaron antes.
En particular haría una nueva consulta a la BD (vía repository)
Marcelo

Felix

unread,
Aug 6, 2013, 3:40:08 PM8/6/13
to symfo...@googlegroups.com
Ya lo logré. Este es el código.
Muchas gracias.
 
          try {
                $em->remove($entity);
                $em->flush();
            } catch (\Doctrine\DBAL\DBALException $e) {
                if ($e->getCode() == 0)
                {
                    if ($e->getPrevious()->getCode() == 23000)
                    {
                        $this->get('session')->getFlashBag()->add('errordelete', "No se puede eliminar porque tiene registros relacionados.");

                        return $this->redirect($this->getRequest()->getRequestUri());
                    }
                    else
                    {
                        throw $e;
                    }
                }
                else
                {
                    throw $e;
                }
            }

aprendizenlared

unread,
Aug 7, 2013, 4:48:02 AM8/7/13
to symfo...@googlegroups.com
Vale vale que PDOException se usaba con versiones antiguas de S2. Sorry no me di cuenta :)

De todas formas a ver si alguien que sepa puede opinar sobre que es mejor?

controlar la excpeción o hacer una comprobación de si tiene datos relacionados para este caso :) Porque estuve buscando en internet pero no encontré info :)


Gracias por compartir la solución :)
Reply all
Reply to author
Forward
0 new messages