首页 > 解决方案 > 将 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_idNULLNOT NULL

  1. 这意味着会有 0 的行和null两者都表示没有关系的行
  2. 使用该表的现有应用程序期望int返回,这意味着需要重构大量代码(更不用说以非常不同的方式处理 null 和 0 的查询)

我想对现有数据库进行改造 Doctrine 必须是人们做的事情,所以我想知道是否有另一种不涉及数据库级别更改的解决方案。似乎某种捕获空值并将其转换为 0 的后处理器会起作用,但我不确定如何实现这一点。

标签: phpmysqldoctrine-orm

解决方案


试试这个

$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 而不是整个实体管理器)

作为旁注,您需要从上面的表查询中添加自动增量(我想它是复制/粘贴错误)


推荐阅读