Коллекции\Criteria:: expr(), isNotNull и notLike

Я использую Doctrine\Common\Collections\Criteria::expr() ( НЕ выражение построителя запроса).

Похоже, что операторы isNotNull() и notLike() не реализованы в этом классе.

Каков наилучший способ сделать isNotNull() и notLike() в этом случае?

Ответ 1

Чтобы иметь значение is not null которое действует как Criteria::expr()->isNotNull('field') вы можете использовать

$criteria = Criteria::create();
$expr = $criteria::expr();
$collection->matching($criteria->where($expr->neq('field', null)));

Это совпадает с тем, как построитель выражений создает isNull но изменяет оператор сравнения на NEQ через.

return new Comparison($field, Comparison::EQ, new Value(null));

Который затем проверяется QueryExpressionVisitor и BasicEntityPersister, используемыми для построения запроса.

Для функциональности Criteria::expr()->like() Criteria::expr()->contains('property', 'value') является эквивалентом property LIKE %value% SQL property LIKE %value%. Однако он не допускает изменения в value% или %value но запрашивает извлечение (по состоянию на 2.5.4) с предлагаемыми startsWith и endsWith использования, которые были объединены с главным, - поэтому может быть выпущено с 2.5.5.

К сожалению, для Criteria::expr()->notLike() и других вариантов LIKE, \Doctrine\Common\Collections\ExpressionBuilder используемый Criteria, не поддерживает их.

Кроме того, если оператор сравнения не определен (например, CONTAINS), QueryExpressionVisitor и BasicEntityPersister, которая не позволяет вручную определять собственную функцию Comparison.

https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#filtering-collections


Лучшей альтернативой является использование собственного репозитория и выражений построителя запросов DBAL для замены желаемой функциональности.

Использование собственного хранилища сущностей для фильтрации результирующего набора предотвратит полное чтение ваших коллекций и увеличит скорость при использовании кэширования.

https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#custom-repositories


Альтернативой является использование filter для извлечения определенного подмножества объектов в коллекции.

https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class

class MyEntity
{
    public function getCollectionFieldNotLike($value)
    {
        return $this->getCollection()->filter(function($a) use ($value) {
            return (false === stripos($a->getField(), $value));
        });
    }

    public function getCollectionFieldLike($value)
    {
        return $this->getCollection()->filter(function($a) use ($value) {
            return (false !== stripos($a->getField(), $value));
        });
    }
}
$repo->getCollectionFieldNotLike('value');
$repo->getCollectionFieldLike('value');

Для процедурного синтаксиса комбинация обоих на репозитории.

$criteria = Criteria::create();
$expr = $criteria::expr();
$criteria->where($expr->neq('field', null));
$collection = $entityManager->getRepository('app:MyEntity')->matching($criteria);
$collectionNotLike =  $collection->filter(function($a) {
    return (false === strpos($a->getField(), 'value'));
});

Имейте в виду, что, как указано выше, это приведет к полному чтению таблицы из коллекции, поскольку для фильтрации результатов потребуется извлечь записи.