如何在Symfony2中处理SQL触发器?

Got*_*bel 6 triggers symfony doctrine-orm

User我的Symfony2/Doctrine2 webapp中有一个实体.此用户具有last_updated标识最新时间的属性,任何内容都已更改.我NOT NULL在我的数据库中设置了这个属性.到现在为止还挺好.

我认为在数据库中创建一个SQL触发器是一种很好的做法,它可以将其设置last_updatedNOW()每个INSERT或每个UPDATE.因此,您不必在应用程序中关注此问题.这就是我所做的,我在我的数据库中实现了这个触发器.

但是如果我现在在我的应用程序中创建一个用户

$user = new User();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
Run Code Online (Sandbox Code Playgroud)

我收到Symfony的错误消息:

'INSERT INTO User (username, ..., last_updated) VALUES (?, ..., ?)' 使用params 执行时发生异常["johndoe", ..., null]:

SQLSTATE [23000]:完整性约束违规:1048列'last_updated'不能为空

问题很明显:Symfony尝试INSERT使用参数nullfor 来触发数据库last_updated,这是不允许的 - 因为此属性可能不为null.

我可以很快想到两个解决方法:

  • 一种解决方法是last_updated从实体描述中取出该字段.然后Symfony不会尝试将任何内容传递给此列的数据库,触发器将设置适当的值.但我认为这不是一个好方法,因为只要我尝试更新db schema(doctrine:schema:update --force),我就会松开我的last_updated列.
  • 另一个解决方法:$user->setLastUpdated(new \DateTime())在我persist()和之前做flush().但这会最大限度地减少在我的数据库上使用触发器的优势,以避免在我的应用程序中关心它.

有没有办法让Symfony/Doctrine知道我的数据库上有一个触发器?如果没有,(如何)我可以挂钩到Symfony/Doctrine来实现正确的解决方法?

Cha*_*ase 11

引用Google群组对此问题的回复:

数据库端代码(例如触发器和函数)倾向于破坏使用ORM(如Propel或Doctrine)开发软件的好处,因为使用ORM的最大优势之一是与数据库无关.通过使用数据库端触发器和函数,您将自己绑定到数据库,因此使用ORM几乎没有任何好处.-GarethMc

https://groups.google.com/forum/#!topic/symfony-users/MH_ML9Dy0Rw

为此,最好使用Faery建议的生命周期回调.一个简单的函数将处理更新该字段,以便您在将来决定更改数据库时不必担心它.

//In Your Entity File EX: SomeClass.php
/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class SomeClass
{
    ....

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function prePersistPreUpdate()
    {
        $this->last_modified = new \DateTime();
    }
}
Run Code Online (Sandbox Code Playgroud)

另请参阅生命周期回调的参考

在您的情况下,您将生命周期回调函数和注释添加到您的用户实体类.SomeClass只是一个示例类,显示生命周期回调不仅仅适用于您的用户实体.


Hai*_*ian 5

另一个(更简单,更通用)选项是使用TimestampableGedmo 的Doctrine扩展.通过这种方式,您可以简单地注释您的实体字段,以便在创建或更新时加上时间戳.

例:

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

class MyEntity
{
    ...

    /**
     * @var \DateTime $lastUpdated
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(name="last_updated", type="datetime")
     */
    private $lastUpdated;

    ...
}
Run Code Online (Sandbox Code Playgroud)

https://packagist.org/packages/gedmo/doctrine-extensions

  • 由于我提出了我的问题,我对Gedmo感到沮丧并且喜欢时间戳和其他人(可登录是另一个杀手插件!).所以,谢谢你在这里提到它! (2认同)