我的Symfony2 / Doctrine2 webapp中有一个User
实体。此用户具有属性last_updated
以标识最新时间,任何内容都已更改。我在我的数据库中将此属性设置为NOT NULL
。到目前为止,非常好。
我认为在数据库中创建SQL触发器是一种很好的做法,它会在last_updated
或NOW()
上将此INSERT
设置为UPDATE
。因此,您不必在应用程序中关注此问题。这就是我所做的,我在我的数据库中实现了这个触发器。
但如果我现在在我的应用中创建用户
$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尝试使用INSERT
null
的{{1}}语句向数据库发出last_updated
- 这是不允许的 - 因为此属性可能不是空。
我可以很快想到两个解决方法:
last_updated
字段。然后Symfony不会尝试将任何内容传递给此列的数据库,触发器将设置适当的值。但我认为这不是一个好方法,因为只要我尝试更新数据库架构(doctrine:schema:update --force
),我就会丢失last_updated
- 列。$user->setLastUpdated(new \DateTime())
和persist()
之前完成flush()
。但这样可以最大限度地减少在我的数据库中使用触发器的优势,以避免在我的应用程序中关注它。有没有办法让Symfony / Doctrine知道我的数据库上有一个触发器?如果没有,(如何)我可以挂钩到Symfony / Doctrine来实现正确的解决方法?
答案 0 :(得分: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();
}
}
另请参阅生命周期回调的参考资料
在您的情况下,您可以将生命周期回调函数和注释添加到User实体类。 SomeClass只是一个示例类,显示生命周期回调不仅仅适用于您的用户实体。
答案 1 :(得分:5)
另一个(更简单,更通用)选项是使用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;
...
}