php - 将 Doctrine 添加到遗留数据库,而不是空连接字段会导致违反完整性约束
问题描述
我正在尝试在现有的大型数据库上改造 Doctrine。该数据库如何处理外键存在问题。作为一个精简的例子,我们有一个表格:
CREATE TABLE `users` (
`user_id` bigint(20) NOT NULL,
`created` datetime NOT NULL,
`org_id` bigint(20) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `orgs` (
`org_id` bigint(20) NOT NULL,
PRIMARY KEY (`org_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
然后是与该表匹配的实体:
/**
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User {
/**
* @ORM\Id
* @ORM\Column(type="bigint")
* @ORM\GeneratedValue
*/
protected $user_id;
/**
* @ORM\Column(type="datetime")
*/
protected $created;
/**
* @ORM\ManyToOne(targetEntity="Org")
* @ORM\JoinColumn(name="org_id", referencedColumnName="org_id")
*/
protected $org;
}
/**
* @ORM\Entity
* @TORM\able(name="orgs")
*/
class Org {
/**
* @ORM\Id
* @ORM\Column(type="bigint")
* @ORM\GeneratedValue
*/
protected $org_id;
}
用户不链接到组织是合法的。在数据库中,用户看起来像:
{
"user_id": 1,
"org_id": 0
}
但是,当尝试插入新行时:
$user = new User;
$em->persist($user);
$em->flush();
出现错误:
PDO Exception: An exception occurred while executing 'INSERT INTO users (created, org_id) VALUES (?, ?)' with params ["2020-12-11 14:41:27", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'org_id' cannot be null
因此,Doctrine 认为它插入的地方似乎没有任何关系null
。因此,我可以通过将列更改为而不是. 然而:org_id
NULL
NOT NULL
- 这意味着会有 0 的行和
null
两者都表示没有关系的行 - 使用该表的现有应用程序期望
int
返回,这意味着需要重构大量代码(更不用说以非常不同的方式处理 null 和 0 的查询)
我想对现有数据库进行改造 Doctrine 必须是人们做的事情,所以我想知道是否有另一种不涉及数据库级别更改的解决方案。似乎某种捕获空值并将其转换为 0 的后处理器会起作用,但我不确定如何实现这一点。
解决方案
试试这个
$default = $em->find('Org', 0);
$user = new User;
$user->setDefaultOrg($default);
$user->created = new DateTime();
$em->persist($user);
$em->flush();
然后在您的用户类中
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
* @ORM\Table(name="users")
*/
class User {
protected $default_org;
/**
* @ORM\ID
* @ORM\Column(type="bigint")
* @ORM\GeneratedValue
*/
protected $user_id;
/**
* @ORM\Column(type="datetime")
*/
public $created;
/**
* @ORM\ManyToOne(targetEntity="Org", cascade={"persist"})
* @ORM\JoinColumn(name="org_id", referencedColumnName="org_id")
*/
protected $org;
/**
* @ORM\PrePersist()
*/
public function fixLegacyOrg()
{
if (is_null($this->org)) {
$this->org = $this->default_org;
}
}
public function setDefaultOrg(Org $org)
{
$this->default_org = $org;
}
}
取决于您的测试需要,您可以注入构造函数(理想情况下只是 Org 而不是整个实体管理器)
作为旁注,您需要从上面的表查询中添加自动增量(我想它是复制/粘贴错误)
推荐阅读
- python - 如何通过模型管理器分别查询设置管理员 django 和休息 api?
- node.js - 将数组从服务器发送到客户端 NodeJ
- linux - 期望脚本无法将密码发送到 cryptsetup
- python - 加载和编译 Keras 模型的问题
- javascript - 通过 sendgrid (node.js) 使用动态模板
- python - 从列表选择中删除数据框中的几列
- javascript - 如何将 arr.includes() 与对象一起使用
- python - 如何直接从python脚本关闭命令提示符?
- mysql - 如果找到数字并插入新列mysql,如何拆分?
- javascript - 未处理的拒绝 (FirebaseError):使用无效数据调用的函数 DocumentReference.set()