2010-05-08 10 views
2

Chaque fois que j'insère une entité qui existe déjà dans la base de données, j'obtiens une erreur car il existe une contrainte unique sur l'un des champs (email). Donc, je veux vérifier si elle existe déjà; sinon, je l'insère.Vérifiez si l'entité existe déjà dans la base de données avant d'insérer avec Doctrine

Mon code ressemble à ceci:

$q = Doctrine_Query::create() 
    ->from('User u') 
    ->where('u.email = ?', $email); 

$object = $q->fetchOne(); 

if(! is_object($object)) { 
      $user = new User(); 
      $user-email = $email; 
      $user->save(); 
    } 

est-il un moyen plus facile de le faire?

Répondre

8

Mettez le code que vous avez dans une méthode dans votre classe USERTABLE par exemple insertIfNotExists():

public function insertIfNotExists(User $user) 
{ 
    // Check if it exists first 
    $q = self::create("u") 
    ->where("u.email = ?", $user->email) 
    ->execute(); 

    // Do we have any? 
    if ($q->count()) 
    { 
    // Yes, return the existing one 
    return $q->getFirst(); 
    } 

    // No, save and return the newly created one 
    $user->save(); 
    return $user; 
} 

Maintenant, vous pouvez appeler la méthode et l'objet retourné sera le dossier existant (s'il y en a un), ou celui que vous venez de créer.

1

J'ai été confronté à un problème similaire lors de la construction d'un enregistreur soutenu par la base de données. Pour éviter la fatigue d'avertissement, j'attribue à chaque message un UID qui est un hachage de son contenu d'identification et fait de l'UID une clé unique. Naturellement, cela nécessite que je détermine si un enregistrement existe déjà qui correspond à cette valeur UID (dans mon cas, j'incrémente une valeur count pour cet enregistrement de journal et touche son horodatage updated_at).

Je fini remplaçant Doctrine_Record::save() dans ma classe de modèle, de façon similaire à ce (code ajustée pour être plus pertinent à votre situation):

/** Persists the changes made to this object and its relations into the 
    * database. 
    * 
    * @param $conn Doctrine_Connection 
    * @return void 
    */ 
    public function save(Doctrine_Connection $conn = null) 
    { 
    /* Invoke pre-save hooks. */ 
    $this->invokeSaveHooks('pre', 'save'); 

    /* Check to see if a duplicate object already exists. */ 
    if($existing = $this->getTable()->findDuplicate($this)) 
    { 
     /* Handle duplicate. In this case, we will return without saving. */ 
     return; 
    } 

    parent::save($conn); 
    } 

UserTable::findDuplicate() ressemble à ceci:

/** Locates an existing record that matches the specified user's email (but 
    * without matching its PK value, if applicable). 
    * 
    * @param $user User 
    * 
    * @return User|bool 
    */ 
    public function findDuplicate(User $user) 
    { 
    $q = 
     $this->createQuery('u') 
     ->andWhere('u.email = ?', $user->email) 
     ->limit(1); 

    if($user->exists()) 
    { 
     $q->andWhere('u.id != ?', $user->id); 
    } 

    return $q->fetchOne(); 
    } 

Notez que C'est probablement une meilleure approche pour remplacer preSave() plutôt que save() dans votre modèle. Dans mon cas, j'ai dû attendre que les hooks de pré-sauvegarde soient exécutés (l'UID a été défini en utilisant un Doctrine template that I had created), donc j'ai dû remplacer save() à la place.

-7

Vous devez utiliser la file d'attente Memcached ou Redis pour vérifier si l'élément existe ou non.