php设置外键约束,关于php:禁用教义外键约束

我在其中一个模型上有关系:

/**

* @ORM\ManyToOne(targetEntity="Page", cascade="persist")

* @ORM\JoinColumn(name="page_id", referencedColumnName="id")

*/

private $parentPage;

当我删除父页面时,出现此错误:

Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails

基本上,我的模型是页面和页面修订。 删除页面时,我不想删除修订。 我还想在页面修订版本中保留page_id(即,不要将其设置为null)。

我该如何使用Doctrine?

抱歉,我的投票有误,我误解了你的问题。您需要做的是删除实际的外键约束。如果约束是通过Doctrine创建的,则您希望将其配置为不再执行此操作,或者只需要继续删除它即可

@Phil Doctine虽然正在生成模式,但我不知道如何告诉它不添加约束。

另一种选择是添加一个属性(例如enabled),该属性将从搜索中排除该页面。这样做会产生删除页面的效果,而不会违反外键约束。

我环顾四周,也找不到任何实质性的东西。您可以尝试运行创建后脚本来删除约束。也许您可以更改为不支持外键的MyISAM表。

@Phil我认为即使如此,从学说的角度来看,数据不一致可能还会有其他问题。我建议实现页面的软删除(在这种情况下是我的最爱)或将page_id列复制为"备份",然后在删除页面时在page_id上设置null。

@dragoste似乎OP实际上希望数据不一致。我认为上述geoBs软删除评论也是最好的解决方案

软删除可能是最正确的解决方案,但是更改应用程序的所有其他部分以过滤出删除的实体会很费时间。切换到MyISAM也可以,这是我所做的,但是并不理想。

@Petah如果您使用gedmo实现软删除,则无需更改任何内容即可过滤出删除的实体,只需将过滤器作为默认添加到配置文件doctrine: orm: entity_managers: default: filters: softdeleteable: [class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter & enabled: true]中即可。然后,只要您想获取已删除的实体,就暂时禁用过滤器$filters = ...->get(doctrine)->getEntityManager()->getFilters(); $filters->disable(softdeleteable); query then enable

根据定义,您不能在不将外键设置为null(onDelete="SET NULL")或级联删除操作的情况下删除外键指向的记录(有两个选项-ORM级别:cascade={"remove"} |数据库级别:onDelete="CASCADE") 。可以为仍然存在的记录设置默认值,但是您必须手动执行此操作,我不认为Doctrine支持此out-of-the-box(如果我输入错误,请更正我,但在这种情况下,请设置默认值)值也不是必需的)。

这种严格性反映了具有外键约束的概念。就像@Théo说的那样:

a FK is to ensure data consistency.

软删除(已经提到)是一种解决方案,但是您也可以做的是添加一个附加的removed_page_id列,该列与page_id同步,然后在preRemove事件处理程序(生命周期回调)中将其删除。这些信息是否具有任何价值,我想知道,但是我想您对此有一定用处,否则您不会问这个问题。

我绝对不是在说这是一种好习惯,但是至少可以将其用于边缘情况。所以符合以下条件:

在您的Revision中:

/**

* @ORM\ManyToOne(targetEntity="Page", cascade="persist")

* @ORM\JoinColumn(name="page_id", referencedColumnName="id", onDelete="SET NULL")

*/

private $parentPage;

/**

* @var int

* @ORM\Column(type="integer", name="removed_page_id", nullable=true)

*/

protected $removedPageId;

然后在您的Page中:

/**

* @ORM\PreRemove

*/

public function preRemovePageHandler(LifecycleEventArgs $args)

{

$entityManager = $args->getEntityManager();

$page = $args->getEntity();

$revisions = $page->getRevisions();

foreach($revisions as $revision){

$revision->setRemovedPageId($page->getId());

$entityManager->persist($revision);

}

$entityManager->flush();

}

或者,您当然可以在构造Revision的过程中已经设置了正确的$removedPageId值,那么您甚至不需要在remove上执行生命周期回调。

保证的约束要求额外的计算资源。 应用程序服务器比数据库服务器更易于水平扩展,因此应将约束放在业务逻辑中。

您明确要求数据不一致,但是我敢肯定您确实不希望这样做。我无法想到这种情况是可以辩护的。这是一个不好的做法,肯定会引起问题。例如:$revision->getPage()的预期结果是什么?

有一个非常简单而优雅的解决方案:可软删除。基本上,它为您的实体添加了一个名为deletedAt的属性(换句话说:向表中添加了列),以存储是否(或最好是:何时)删除该实体。因此,如果该属性为null,则不会删除该实体。

唯一要做的就是添加此捆绑包,向您的实体(Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity)添加特征,并更新数据库。实现非常简单:此程序包将为您完成工作。阅读文档以了解此扩展。

或者,您可以添加"已启用"布尔值属性或状态字段(例如"已发布","草稿","已删除")。

When I delete the page I don't want to delete the revisions. I also want to keep the page_id on the page revisions (i.e. not set it to null).

我认为您已经得到了答案:教条不会这样做,仅仅是因为它与外键的概念无关。 FK的原理是确保数据一致性,因此,如果您有FK,则必须引用现有ID。删除时,某些数据库引擎(例如,用于MySQL的InnoDB)允许您将FK放入null(假设您确实使FK列可为空)。但是,引用不存在的ID是不可行的,或者它不是FK。

如果您确实想这样做,请不要在这种情况下使用Doctrine,这不会阻止您在代码库的其他地方使用Doctrine。另一种解决方案是仅手动将FK约束放到后面,或在查询之前使用DB语句跳过FK检查。

MySQL不是数据库引擎,而是DBMS。 MySQL的流行数据库引擎(InnoDB和MyISAM)与外键的处理方式不同。 如果您想了解更多信息,请阅读以下问题:stackoverflow.com/questions/12614541/

没错,经过修改可以反映出这一点

以及如何手动将FK约束放到后面?

$objectManager->getConnection()->exec(SET FOREIGN_KEY_CHECKS = 0;);

您可以禁用特定模型的外键导出:

User:

attributes:

export: tables

columns:

现在,它将仅导出表定义,不导出任何外键。您可以使用:无,表,约束,插件或全部。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值