Symfony Migrations Bundle重复生成相同迁移问题求助
Doctrine的Schema对比机制在处理自定义columnDefinition时,会将实体映射定义与数据库information_schema中存储的字段元数据做精确匹配。对于MySQL的TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,数据库存储的元数据格式可能和你在columnDefinition中编写的存在细微差异(比如空格、大小写或语法顺序),导致Doctrine每次对比都判定字段定义不匹配,重复生成修改语句。
另外,generated: "ALWAYS"的配置会让Doctrine认为该字段值完全由数据库生成,但它无法正确识别ON UPDATE这种数据库层面的自动更新逻辑,进一步加剧了对比时的不匹配判定。
方法一:改用Doctrine生命周期回调(推荐)
放弃数据库层面的自动时间戳,改用Doctrine的生命周期事件控制时间戳,让Doctrine完全掌控字段映射逻辑,避免重复生成迁移:
#[Entity] class Article { #[Column(type: "datetime")] public \DateTimeInterface $created; #[Column(type: "datetime")] public \DateTimeInterface $updated; #[PrePersist] public function setCreatedValue(): void { $this->created = new \DateTimeImmutable(); $this->updated = new \DateTimeImmutable(); } #[PreUpdate] public function setUpdatedValue(): void { $this->updated = new \DateTimeImmutable(); } }
执行php bin/console make:migration生成迁移后,后续再执行该命令就不会重复生成修改语句。
方法二:调整实体映射配置(适配数据库层面定义)
如果坚持使用数据库层面的自动时间戳,可修改实体映射避免columnDefinition的精确匹配问题:
针对MySQL的优化配置
#[Entity] class Article { #[Column( type: "datetime", options: [ 'default' => 'CURRENT_TIMESTAMP', 'on_update' => 'CURRENT_TIMESTAMP' ], insertable: false, updatable: false, generated: 'ALWAYS' )] public \DateTimeInterface $created; }
Doctrine会将options中的参数转换为数据库原生语法,且能正确识别数据库返回的元数据,避免重复对比差异。
强制Doctrine忽略字段对比(不推荐)
如果上述方法无效,可通过自定义SchemaFilter让Doctrine忽略该字段的对比检查,但这会隐藏其他可能的字段变更,需谨慎使用:
在config/packages/doctrine.yaml中添加配置:
doctrine: dbal: schema_filter: ~^(?!article\.created$)~
内容的提问来源于stack exchange,提问作者CunningFatalist

