【问题标题】:How to handle SQL triggers in Symfony2?如何在 Symfony2 中处理 SQL 触发器?
【发布时间】:2020-03-24 05:34:09
【问题描述】:

我的 Symfony2/Doctrine2 webapp 中有一个 User 实体。这个用户有一个属性last_updated 来标识最近的时间,一切都发生了变化。我在我的数据库中将此属性设置为NOT NULL。到目前为止,一切顺利。

我认为在数据库中创建一个 SQL 触发器是一种很好的做法,它将每个 INSERTUPDATE 上的 last_updated 设置为 NOW()。所以你不必在你的应用程序中关心这个。这就是我所做的,我在我的数据库中实现了这个触发器。

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

$user = new User();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();

我收到 Symfony 的错误消息:

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

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

问题很明显:Symfony 正在尝试使用参数 nulllast_updated 向数据库触发 INSERT 语句,这是不允许的 - 因为此属性可能不为空。

我很快想到了两种解决方法:

  • 一种解决方法是从实体描述中删除last_updated 字段。然后 Symfony 不会尝试为此列向数据库传递任何内容,触发器会设置适当的值。但我认为这不是一个好方法,因为一旦我尝试更新数据库架构 (doctrine:schema:update --force),我就会失去我的 last_updated-column。
  • 另一种解决方法:只需在 persist()flush() 之前执行 $user->setLastUpdated(new \DateTime())。但这会最大限度地减少在我的数据库上使用触发器的优势,以避免在我的应用程序中关心它。

有什么方法可以让 Symfony/Doctrine 知道我的数据库上有一个触发器在运行?如果没有,(如何)我可以连接到 Symfony/Doctrine 以实施适当的解决方法?

【问题讨论】:

标签: symfony doctrine-orm triggers


【解决方案1】:

引用 google 小组对此问题的回复:

数据库端代码(例如触发器和函数)往往会破坏使用像 Propel 或 Doctrine 这样的 ORM 开发软件的好处,因为使用 ORM 的最大优势之一是与数据库无关。通过拥有数据库端触发器和函数,您将自己绑定到数据库,因此使用 ORM 几乎没有任何好处。 -加雷斯麦克

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

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

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

【讨论】:

  • 随便 :) +1。谢谢!
【解决方案2】:

另一个(更简单、更通用)的选择是使用 Gedmo 的 Timestampable 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;

    ...
}

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

【讨论】:

  • 自从我提出问题后,我偶然发现了 Gedmo,并且喜欢 timestampable 和 orthers(loggable 是另一个杀手级插件!)。所以谢谢你在这里提到它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 2015-08-26
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 1970-01-01
相关资源
最近更新 更多