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.
精彩评论