开发者

Check if entity already exists in database before inserting with Doctrine

Whenever I insert an entity that already exists in the database, I get an error because there is a unique constraint on one of the fields (email).

So I want to check if it already exists; if not, I insert it.

My code looks like this:

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

$object = $q->fetchOne();

if( ! is_object($object)) {
          $user = new User();
          $use开发者_如何转开发r-email = $email;
          $user->save();
    }

Is there an easier way to do this?


Put the code you have into a method in your UserTable class eg 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;
}

Now you can call the method, and the object returned will be the existing record (if there is one), or the one you've just created.


I was faced with a similar problem while building a database-backed logger. To prevent warning fatigue, I assign each log message a UID which is a hash of its identifying content and made the UID a unique key.

Naturally, this requires that I determine whether a record already exists that matches that UID value (in my case, I increment a count value for that log record and touch its updated_at timestamp).

I ended up overriding Doctrine_Record::save() in my model class, similarly to this (code adjusted to be more relevant to your 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() looks like this:

  /** 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();
  }

Note that it is probably a better approach to overwrite preSave() rather than save() in your model. In my case, I had to wait until the pre-save hooks executed (the UID was set using a Doctrine template that I had created), so I had to overwrite save() instead.


You should use Memcached or Redis queue in order to check if item exists or not.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜