我有两个相互引用的实体:一个引用defaultUrl
的Page
实体和一个引用page
的Url
实体。
这是循环的,所以一旦我添加了一个页面和一个相互引用的url,我就不能删除它们。
我可以看到两种方法来修复它,但我不确定"原则"的方法。
- 使其中一个关系仅为索引,而不是外键约束
- 删除时,关闭外键约束检查
我不知道怎么做这些…你知道吗??
谢谢!
这是Doctrine的设置方法。如前所述,您需要将至少一个外键设置为可空的。
还考虑将onDelete级联设置为SET NULL。这将使删除过程更加简单——您不必在删除记录之前将键更新为NULL。
你的模式。Yml看起来像这样:
Url:
columns:
page_id: { type: integer, notnull: true }
relations:
Page: { local: page_id, foreign: id }
Page:
columns:
default_url_id: { type: integer, notnull: false } # ALLOWS NULL foreign key here
relations:
DefaultUrl: { class: Url, local: default_url_id, foreign: id, onDelete: SET NULL }
根据经验,在制作外键时,总是让一个外键定义为空或省略一个外键定义。
允许循环中断。
最简单的情况(SQL语法,但适用抽样原则):
CREATE TABLE Employee (
EmployeeId INTEGER NOT NULL IDENTITY(1,1)
ManagerId INTEGER NOT NULL
--...
PRIMARY KEY EmployeeId NONCLUSTERED
FOREIGN KEY FK_Manager REFRENCES Employee(EmployeeId)
)
可以按如下方式断开循环:
CREATE TABLE Employee (
EmployeeId INTEGER NOT NULL IDENTITY(1,1)
ManagerId INTEGER NOT NULL
--...
PRIMARY KEY EmployeeId NONCLUSTERED
)
或如下:
CREATE TABLE Employee (
EmployeeId INTEGER NOT NULL IDENTITY(1,1)
ManagerId INTEGER NULL
--...
PRIMARY KEY EmployeeId NONCLUSTERED
FOREIGN KEY FK_Manager REFRENCES Employee(EmployeeId)
)
在声明外键时,我更喜欢始终跟踪关系图并确保没有循环。我将省略最不危险的键,直到所有循环都被打破。这确保了所有表都可以批量导出,然后批量导入到另一个数据库。
编辑:我发现当你问一个书籍专家这个问题时,你得到的答案是在删除时关闭外键。这是错误的,原因有二。首先,正常的事务操作不应该改变模式定义。其次,代码的其余部分期望外键在那里,因此不在应用程序代码中处理它;然而,模式修改有一个坏习惯,即跨事务流血或锁定整个表。