2012-09-05 5 views
9

Quindi, dopo una violazione del vincolo di integrità che utilizza Doctrine2, EntityManager si avvicina alla chiusura in modo tale da rendere impossibile continuare a utilizzare EntityManager. Il pensiero prevalente sembra essere che dovresti creare un nuovo EntityManager invece di essere in grado di cogliere questa semplice eccezione e gestirla in modo aggraziato (meraviglioso design là ragazzi/sarcasmo).Gestione di un EntityManager chiuso con Bisna/Doctrine2

Tuttavia, si presenta un problema quando si utilizza la libreria Bisna/ZF 1.12 con un gestore entità chiuso. La libreria Bisna non prevede un metodo pubblico per creare un nuovo EntityManager con lo stesso nome (cioè "predefinito") dopo che è stato chiuso nella classe Container.

La mia domanda è qual è il modo migliore per affrontare questo problema. Semplicemente deve esserci un modo per recuperare con garbo dopo una violazione del vincolo di integrità.

+0

utilizzando il Registro di dottrina potrebbe ripristinare un gestore di entità chiusa. – Florian

+0

consulta https://github.com/symfony/symfony/issues/5339 – Florian

risposta

2

Invece di cercare di recuperare da queste situazioni, si dovrebbe concentrarsi sulla prevenzione integrità violazioni di vincoli:

  • Se si colpisce un vincolo di chiave esterna, non si sta legando le entità insieme nel giusto maniera.
  • Se si colpisce un vincolo univoco, è necessario controllare il db per possibili dati duplicati prima di tentare di mantenerlo.
  • Se si colpisce un altro tipo di vincolo e non sanno come prevenirla, si prega di chiedere :)

UPDATE:

Il motivo Doctrine2 chiude l'EntityManager è perché nella maggior parte dei casi è non è più sicuro da usare. Il suo UnitOfWork contiene operazioni che non possono essere eseguite (da qui l'eccezione che viene lanciata).

È corretto che la libreria Bisna non supporti la creazione di un nuovo EntityManager. Puoi estenderlo per implementare tale funzionalità da solo.

Un'altra soluzione potrebbe essere quella di handle transactions manually:

$em->getConnection()->beginTransaction(); // suspend auto-commit 
try { 
    // do some work 
    $user = new User; 
    $user->setName('George'); 
    $em->persist($user); 
    $em->flush(); 
    $em->getConnection()->commit(); 
} catch (Exception $e) { 
    $em->getConnection()->rollback(); 
    $em->clear(); // in stead of $em->close(); 
    throw $e; 
} 

Sostituendo $em->close() con $em->clear() si mantiene l'EntityManager aperto e pulito per usare di nuovo.

ho altamente incoraggio a uno vicino o chiaro l'EntityManager, in quanto i dati in essa è (quasi sempre) non è più utilizzabile.

+1

Ci sono degli scenari in cui non puoi saperlo prima. Un semplice esempio sono i client multipli connessi al database, che è ovviamente comune. Possono inserire dati duplicati subito dopo aver effettuato il check-in ma prima che il client li abbia salvati. Semplicemente non puoi impedirlo, solo usando blocchi di database di tipo esclusivo (e non li vogliamo davvero). Quindi il recupero da questo tipo di errore è piuttosto essenziale. –

+0

Sono d'accordo che dovresti recuperare in questo caso particolare, ma molto probabilmente non avrà bisogno di un nuovo EntityManager nella stessa richiesta (perché l'utente/cliente ha bisogno di rivalutare il suo/il suo input). PS: Doctrine fornisce il blocco, vedi http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#version e http://docs.doctrine-project.org /en/2.0.x/reference/transactions-and-concurrency.html#locking-support –

0

Gestire manualmente le transazioni non sembra fare il trucco per me. Doctrine ha comunque chiuso l'Entity Manager anche se ho usato solo il metodo clear. Ho biforcato Bisna e ho apportato alcune modifiche alla classe Container, aggiungendo un metodo "resetEntityManager", che sembra funzionare perfettamente.

Così ora il mio codice è simile al seguente:

try { 
    $user = new User; 
    $user->setName('George'); 
    $em->persist($user); 
    $em->flush(); 
} catch (Exception $e) { 
    $dc = \Zend_Registry::get('doctrine'); //returns Bisna\Doctrine\Container 
    $em = $dc->resetEntityManager(); //returns the new instance 
    throw $e; 
} 

classe Container Revised è qui:

https://github.com/ajlozier/zendframework1-doctrine2/blob/ea46703e909149cba43edca56c91d5de2ab7a7f9/library/Bisna/Doctrine/Container.php

Problemi correlati