Доктрина 2: Используйте значения по умолчанию 0 вместо null для отношения

можно ли использовать значение 0 вместо null для отношений (многие-к-одному, один-к-одному) с Doctrine 2?

теперь у меня есть много не нулевых столбцов, которые я не могу изменить на нулевые значения. Изменение значения по умолчанию в MySQL на 0 не является решением, потому что доктрина всегда устанавливает столбец для вставки / обновления строк.

1 ответов


нет, это невозможно.

NULL имеет очень специфическое значение в SQL. Он представляет собой "нет значения", и вы можете убедиться, что ваша логика не будет работать даже на уровне SQL:

CREATE TABLE foo (
    `id` INT(11) PRIMARY KEY AUTO_INCREMENT,
    `bar_id` INT(11)
);

CREATE TABLE `bar` (`id` INT(11) PRIMARY KEY AUTO_INCREMENT);

ALTER TABLE foo ADD FOREIGN KEY `bar_id_fk` (`bar_id`) REFERENCES `bar` (`id`);

INSERT INTO `bar` VALUES (NULL);
INSERT INTO `bar` VALUES (NULL);
INSERT INTO `bar` VALUES (NULL);
INSERT INTO `foo` VALUES (NULL, 1);
INSERT INTO `foo` VALUES (NULL, 2);
INSERT INTO `foo` VALUES (NULL, 3);
INSERT INTO `foo` VALUES (NULL, 0);

/*
    ERROR 1452 (23000): 
        Cannot add or update a child row: a foreign key constraint fails
        (`t2`.`foo`, CONSTRAINT `foo_ibfk_1` FOREIGN KEY (`bar_id`) 
        REFERENCES `bar` (`id`))
*/

INSERT INTO `foo` VALUES (NULL, 4);

/*
    ERROR 1452 (23000): 
        Cannot add or update a child row: a foreign key constraint fails
        (`t2`.`foo`, CONSTRAINT `foo_ibfk_1` FOREIGN KEY (`bar_id`) 
        REFERENCES `bar` (`id`))
*/

INSERT INTO `foo` VALUES (NULL, NULL); /* VALID! */

так нет, вы не можете иметь учение ОРМ вести себя так, чтобы 0 трактуется как NULL, поскольку это не разрешено самой СУБД.

что вы можете сделать, это вставить "поддельные" ссылки в вашу БД, которые затем будут действовать как null объект когда гидратированные как сущности:

INSERT INTO `bar` VALUES (NULL);
UPDATE `bar` SET `id` = 0 WHERE `id` = 4;

INSERT INTO `foo` VALUES (NULL, 0); /* now works! */

в терминах сущности, это выглядит довольно похоже.

(обратите внимание, что public свойства поддерживаются только из доктрины ORM 2.4, которая еще не выпущена. Они делают вещи легче читать здесь, хотя)

Фу.на PHP:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="foo")
 */
class Foo
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @ORM\ManyToOne(targetEntity="Bar")
     * @ORM\JoinColumn(name="bar_id", referencedColumnName="id", nullable=false)
     */
    public $bar;
}

бар.на PHP:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="bar")
 */
class Bar
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;
}

и затем код для создания нового Foo например:

$nullBar  = $entityManager->find('Bar', 0);
$foo      = new Foo();
$foo->bar = $nullBar;

$em->persist($foo);
$em->flush();