“定义不完整。需要‘外国’。”关于迁移

问题描述 投票:0回答:1

我正在尝试运行

symfony console make:migration
(也尝试过使用
php bin/console make:migration
,以防万一),但我遇到了错误:

定义不完整。需要“外国”。

这似乎是由我的 OneToMany 字段之一引起的,我尝试修改该字段以更好地适应我的项目。

收到此错误后,我尝试在触发错误的位置放置调试消息,它告诉我错误来自我的Team实体。

注意:我的项目由 3 个实体组成:团队、补丁和游戏。一个团队可以有多个补丁。一款游戏也可以有多个补丁。一个补丁可以链接多个游戏。

当我尝试在TeamPatch之间创建OneToMany字段时,我告诉symfony在Patch中创建“team_id”,但结果是名称team_id_id,这是我不想要的。为了纠正这个问题,我重命名了数据库字段,并对 Patch 实体代码进行了一些调整;添加“名称:'team_id'”,这是部分:

#[ORM\ManyToOne(inversedBy: 'patch_ids')]
#[ORM\JoinColumn(name: 'team_id', nullable: false)]
private ?Team $team_id = null;

它当时有效,但当我尝试向游戏添加一些其他字段(实际上可能是任何实体)时,它似乎会引起一些问题

这是我的第一篇文章,所以如果需要的话请随时询问更多细节。

php symfony doctrine-orm doctrine symfony6
1个回答
0
投票

好吧,这不应该是关于最佳实践的,但确实是这样。

使用 ORM 显然有优点和缺点,你应该意识到。有时,ORM 会从代码中的定义中推导出数据库结构。 symfony 使用的 ORM Doctrine 就是这么做的。

这意味着,如果您的数据库在阅读代码后与预期的有所不同,则可能会因更改而阻塞。另外,如果您使数据库陷入不一致状态,则必须自行修复。

可能发生了什么

使用关系字段的迁移还将添加外键,以便根据另一个表的实际主键(例如

patch.team_id
patch.team_id_id
,具体取决于字段)中的条目(例如
team.id
team.team_id
)进行检查在您的命名模式上)。

如果您以某种方式设法仅重命名字段,但没有删除外键并添加正确版本的外键,则您将无法添加更多列,因为架构无效。 Doctrine 给出了外键名称,即其各部分的哈希值,这样就不会出现名称冲突。如果列名称更改,哈希也会更改,因此外键很可能在某种程度上是错误的。

解决问题

正确的方法(供将来参考)是回滚引入了您不喜欢的更改的迁移,然后删除迁移,修复代码/注释/属性中的问题并创建新的移民。教义按照你告诉它的去做,但你可能没有写出你想要的东西(从教义的角度来看)。

因此,这是您的短期救赎之道,恢复迁移中的更改,尤其是外键 - 如果您不知道它们是什么:请阅读。

使用学说的检查映射/模式能力也可能有所帮助。

建议

理解 Doctrine(也许是一般的 ORM)。在 Doctrine 中,你永远不应该有一个 field (php 属性)

team_id
,即使你有一个 column
team_id
(db 列)。该字段应命名为
team
,因为它是类型为
Team
?Team
实体。如果字段包含实体,Doctrine 将在列名称中添加
_id
。 (这将消除您添加 JoinColumn 名称的需要)

Doctrine 将对象(关系)层 - “一个补丁可能有一个团队” - 映射到数据库层:“补丁表有一个

team_id
,这是一个引用
team.id
的外键”,它可以使大多数数据库的东西更容易。结果通常应该是,您不应该过多考虑数据库中的内容,只需编写面向对象的代码即可。

您也不应该编写 SQL,而应该编写 DQL(理论查询语言),这是面向对象的替代方案。 Doctrine 会将其转化为 SQL。这就是 ORM 方式。最后,如果您遵循学说为您制定的方式,您的代码可能看起来更优雅。 (但这显然始终是一个意见问题)

ORM 的缺点通常是,虽然它对所有琐碎的事情都更好,但做复杂的事情却要困难得多,这不是 ORM 的初衷(在本例中是教义),而且一些查询/机制效率低下,需要修复这些非常复杂(例如 n+1 问题)。如果您想编写更复杂的查询,但仍然想写出教义的所有优点,那么您可能会被一些丑陋的石头绊倒。 (通常是数据库特定的函数)。

© www.soinside.com 2019 - 2024. All rights reserved.