Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 2: Use default 0 values instead of null for relation

Is it possible to use the value 0 instead of null for relations (many-to-one, one-to-one) with Doctrine 2?

Now I've got a lot of NOT NULL columns witch I may not change to null values. Changing the default value in MySQL to 0 it self isn't the solution becease doctrine always sets the column for inserting/updating rows.

like image 309
Guido Dubois Avatar asked Mar 19 '13 14:03

Guido Dubois


People also ask

Does doctrine validate the length of a string value?

Doctrine does not validate the length of a string value for you. precision: The precision for a decimal (exact numeric) column (applies only for decimal column), which is the maximum number of digits that are stored for the values.

What are the alternatives for returning null values in JavaScript?

Several alternatives for returning null values include using null object reference types, a null object pattern, and a result type as the return type. Therefore, the recommendation is to return an empty value instead of a null to keep the code clean and error-free. Have you ever been in a situation where an application's state changes unexpectedly?

Are database default values portably supported?

Database default values are not "portably" supported. The only way to use database default values is through the columnDefinition mapping attribute where you specify the SQL snippet ( DEFAULT cause inclusive) for the column the field is mapped to.

What is @entity annotation in doctrine?

@Entity Required annotation to mark a PHP class as an entity. Doctrine manages the persistence of all classes marked as entities. Optional attributes: repositoryClass: Specifies the FQCN of a subclass of the EntityRepository.


1 Answers

No, this is not possible.

NULL has a very specific meaning in SQL. It represents "no value", and you can verify that your logic won't work even at SQL level:

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! */

So no, you cannot have Doctrine ORM behave so that 0 is interpreted as NULL, since that's not allowed by the RDBMS itself.

What you can do is inserting "fake" referenced entries in your DB, which will then act as null object when hydrated as entities:

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

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

In entity terms, it looks quite similar.

(Please note that public properties are ONLY supported from Doctrine ORM 2.4, which is not yet released. They make things easier to read here, though)

Foo.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;
}

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;
}

And then the code to produce a new Foo instance:

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

$em->persist($foo);
$em->flush();
like image 146
Ocramius Avatar answered Sep 22 '22 03:09

Ocramius