2

I have a class, let's say Test.php. This class has an id, a description, a code, and a discount percentage.

This code returns an object:

$test = $this->getDoctrine()->getRepository('\UserBundle\Entity\Test')->findOneBy(array('code' => 12345 ));

This code, instead, doesn't return an object:

$test = $this->getDoctrine()->getRepository('\UserBundle\Entity\Test')->findOneBy(array('code' => null ));

The code field is NULL by default.

Any suggestion? Thanks!

ZugZwang
  • 418
  • 1
  • 5
  • 14

3 Answers3

4

Taken from this answer

In SQL, a comparison between a null value and any other value (including another null) a using a logical operator (eg =, !=, <, etc) will result in a null, which is considered as false for the purposes of a where clause. The reasoning is that a null means "unknown", so the result of any comparison to a null is also "unknown".

To query for a null value you need to use is null rather than = null which the Doctrine shortcut don't do. You would need to do this by using SQL/DQL directly or the query builder like...

/** QueryBuilder */
$test = $this
    ->getDoctrine()
    ->getRepository('\UserBundle\Entity\Test')
    ->createQueryBuilder('t')
    ->where('t.code is null')
    ->getQuery()
    ->getResult();
/**
 * Alternatively, if trying to find a single record you can use ->getOneOrNullResult();
 * as ->getResult() will throw a NoResultException if no results are found
 */

/** DQL */
$test = $this
    ->getDoctrine()
    ->createQuery('
        SELECT t
        FROM \UserBundle\Entity\Test t
        WHERE t.code is null
    ')
    ->getResult()
    ->getOneOrNullResult();
Community
  • 1
  • 1
qooplmao
  • 17,622
  • 2
  • 44
  • 69
  • I got this error using the queryBuilder: Attempted to call method "getResult" on class "Doctrine\ORM\QueryBuilder". – ZugZwang Sep 09 '16 at 12:34
  • Crap.. sorry. I forgot `getQuery()` to actually building the query. Have updated. – qooplmao Sep 09 '16 at 12:36
  • Ok, but now i got this one: Error: Call to a member function getOneOrNullResult() on a non-object. If I comment the ->getOneOrNullResult() and launch var_dump($test), the result is an array. – ZugZwang Sep 09 '16 at 12:43
  • Everything is fine now but when I launch the query with the condition (WHERE t.code is null) I got an empty array, even if I've saved one object with code=NULL. – ZugZwang Sep 09 '16 at 13:05
  • Are you 100% sure that it's null rather than an empty string? Otherwise I'm a bit stumped on what it's not giving you the correct result. – qooplmao Sep 09 '16 at 13:11
  • The code field is NULL by default. In my db I have on field with code = 12345. If I launch the query with the condition (WHERE t.code = 12345) and then var_dump($test) I got array{1} with all the data. Instead, i I launch the query with the condition (WHERE t.code is null) I got array{0} and then nothing. I'm sure 100% that I have a NULL code field. – ZugZwang Sep 09 '16 at 13:15
  • And you get 2 results if you remove the whole `where(...)` line form the query? – qooplmao Sep 09 '16 at 13:18
  • I get array(4), I have 4 lines in the db – ZugZwang Sep 09 '16 at 13:21
  • Then I have no idea without looking at actual code/data. Sorry. It would probably best for you to open another question with your code and data as I'm stumped with what I currently have. – qooplmao Sep 09 '16 at 13:21
  • I've deleted all data in db and created new ones. Now it works fine! Thnx – ZugZwang Sep 09 '16 at 13:30
  • Happy days. Glad to help – qooplmao Sep 09 '16 at 13:31
2

While qooplmao is correct for the first part "To query for a null value you need to use is null rather than = null", I have to say that the second part "which the Doctrine shortcut don't do" is not true (at least for version 2.5.4, which was the latest stable release at the time of the question).

\Doctrine\ORM\EntityRepository::findOneBy() (with argument array('code' => null)) ultimately calls
\Doctrine\ORM\Persisters\Entity\BasicEntityPersister::getSelectConditionStatementSQL() (with arguments 'code', null, null), which does handle the special case of a null value (shortened to the essential here, $columns is an array with a single element e.g. array('t0.code'), $value is null):

        foreach ($columns as $column) {
            $placeholder = '?';

            ...

            if (null === $value) {
                $selectedColumns[] = sprintf('%s IS NULL', $column);
                continue;
            }

            $selectedColumns[] = sprintf('%s = %s', $column, $placeholder);
        }

and then executes a SQL query with a correct condition, of the form:

SELECT t0.id AS id_1, t0.description AS description_2, t0.code AS code_3, ...
FROM Test t0
WHERE t0.code IS NULL
LIMIT 1

(It even handles null in an array value, e.g. with argument array('code' => array(12345, null, 42)), it will generate a SQL condition of the form

WHERE (t0.code IN (12345, NULL, 42) OR t0.code IS NULL)

(actually it could remove the NULL from the IN, but the result is the same).)

Edit: That has been the case since version 2.5.0 for both simple and array values (thanks to commit 733102b4a109c0bb8ca026b1dbbadaa9bb62ae70), and even since version 2.1.0 for simple (non-array) values (like your case) (thanks to commit a3290075260cdafdd17952ca14daa305fabccfe2).


So the fact that your findOneBy(array('code' => null )) didn't return an object can only mean that your table just didn't have any row with column code set to NULL, which seems confirmed by your discussion with qooplmao in the comments of their answer, and so if you retry now with your new data, it should return an object the same as with a QueryBuilder or DQL.

user7426410
  • 71
  • 1
  • 2
0

You just can use doctrine expressions in TestRepository class

$db = $this->createQueryBuilder('t');

return $db->select('t')
    ->where($db->expr()->isNull('t.field1'))
    ->orWhere($db->expr()->isNull('t.field2'))
    ->orWhere($db->expr()->isNull('t.field3'))
    ->getQuery()
    ->getResult();
Stevan Tosic
  • 6,561
  • 10
  • 55
  • 110