Intereting Posts
Как настроить пользовательские заголовки для отдельных действий контроллера в ZF2? Проверка php для сервера NTP Как конвертировать UTC datetime в другой часовой пояс? зарегистрировать js для определенной страницы в script-calls.php получить первый пиксель из изображения, используя php Нужно руководство для начала с Zend ACL PHP Если заявление с несколькими условиями В поле «Автоматическое приращение» введите 1000 в миграции laravel 5.1 PHP – получить количество страниц в документе Word Laravel показывает форму формы с именем элемента формы как ключ читать и искать в pdf-файле Страница обслуживания laravel 5, сломанная во время обновления композитора Лоравельский красноречивый запрос разбиения на несколько этапов Сбой запроса SQL LIKE – фатальная ошибка в подготовленном сообщении Использование MOODLE создает пользователей и регистрирует их на курсах через SQL

Как выбирать случайным образом с доктриной

Вот как я запрашиваю свою базу данных для некоторых слов

$query = $qb->select('w') ->from('DbEntities\Entity\Word', 'w') ->where('w.indictionary = 0 AND w.frequency > 3') ->orderBy('w.frequency', 'DESC') ->getQuery() ->setMaxResults(100); 

Я использую mysql, и я хотел бы получить случайные строки, соответствующие критериям, я бы использовал запрос rand () в моем запросе.

Я нашел этот аналогичный вопрос, который в основном предполагает, поскольку ORDER BY RAND не поддерживается в доктрине, вместо этого вы можете рандомизировать первичный ключ. Однако это не может быть сделано в моем случае, потому что у меня есть критерии поиска и предложение where, чтобы не каждый первичный ключ удовлетворял этому условию.

Я также нашел фрагмент кода, который предполагает, что вы используете OFFSET для рандомизации строк следующим образом:

 $userCount = Doctrine::getTable('User') ->createQuery() ->select('count(*)') ->fetchOne(array(), Doctrine::HYDRATE_NONE); $user = Doctrine::getTable('User') ->createQuery() ->limit(1) ->offset(rand(0, $userCount[0] - 1)) ->fetchOne(); 

Я немного смущен в отношении того, поможет ли это мне обойти отсутствие поддержки заказа случайным в моем случае или нет. Я не смог добавить смещение после setMaxResult.

Есть идеи, как это можно сделать?

Команда Doctrine не желает выполнять эту функцию .

Есть несколько решений вашей проблемы, каждая из которых имеет свои недостатки:

  • Добавьте пользовательскую числовую функцию : см. Эту функцию DQL RAND ()
    (может быть медленным, если у вас много подходящих строк)
  • Использовать собственный запрос
    (Я лично стараюсь избегать этого решения, которое мне было трудно поддерживать)
  • Сначала выполните необработанный SQL-запрос, чтобы получить некоторые идентификаторы случайным образом, затем используйте DQL WHERE x.id IN(?) Для загрузки связанных объектов, передав массив идентификаторов в качестве параметра.
    Это решение включает в себя два отдельных запроса, но может дать лучшую производительность, чем первое решение (существуют другие методы необработанных SQL, чем ORDER BY RAND() , я не буду подробно их описывать здесь, вы найдете некоторые полезные ресурсы на этом сайте).

Следуй этим шагам:

Определите новый класс в своем проекте как:

 namespace My\Custom\Doctrine2\Function; use Doctrine\ORM\Query\Lexer; class Rand extends \Doctrine\ORM\Query\AST\Functions\FunctionNode { public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $parser->match(Lexer::T_CLOSE_PARENTHESIS); } public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { return 'RAND()'; } } 

Зарегистрируйте класс config.yml :

 doctrine: orm: dql: numeric_functions: Rand: My\Custom\Doctrine2\Function\Rand 

Используйте его как:

 $qb->addSelect('RAND() as HIDDEN rand')->orderBy('rand'); 

Или вы можете это сделать ->

 $words = $em->getRepository('Entity\Word')->findAll(); shuffle($words); 

Конечно, это было бы очень неэффективно, если бы у вас было много записей, поэтому используйте их с осторожностью.

Doctrine 2 не поддерживает ORDER BY rand (), но я нашел эту статью, где исправления для этого проблемы.

Почему бы не использовать репозиторий?

 <?php namespace Project\ProductsBundle\Entity; use Doctrine\ORM; class ProductRepository extends ORM\EntityRepository { /** * @param int $amount * @return Product[] */ public function getRandomProducts($amount = 7) { return $this->getRandomProductsNativeQuery($amount)->getResult(); } /** * @param int $amount * @return ORM\NativeQuery */ public function getRandomProductsNativeQuery($amount = 7) { # set entity name $table = $this->getClassMetadata() ->getTableName(); # create rsm object $rsm = new ORM\Query\ResultSetMapping(); $rsm->addEntityResult($this->getEntityName(), 'p'); $rsm->addFieldResult('p', 'id', 'id'); # make query return $this->getEntityManager()->createNativeQuery(" SELECT p.id FROM {$table} p ORDER BY RAND() LIMIT 0, {$amount} ", $rsm); } } 

В соответствии с тем, что предложил Хасан Магди Саад, вы можете использовать популярную библиотеку DoctrineExtensions :

 # config.yml doctrine: orm: dql: numeric_functions: rand: DoctrineExtensions\Query\Mysql\Rand 

Протестировано в Doctrine ORM 2.6.x-dev, вы можете на самом деле:

 ->orderBy('RAND()') 

Перетасовка может быть выполнена по запросу (массив), но перетасовка не выбирается случайным образом.

Чтобы случайно выбирать из объекта, я предпочитаю делать это на PHP, что может замедлить случайный выбор, но это позволяет мне контролировать контроль над тем, что я делаю, и облегчить возможную отладку.

В приведенном ниже примере помещаются все идентификаторы из объекта в массив, который затем я могу использовать для «случайного лечения» в php.

 public function getRandomArt($nbSlotsOnPage) { $qbList=$this->createQueryBuilder('a'); // get all the relevant id's from the entity $qbList ->select('a.id') ->where('a.publicate=true') ; // $list is not a simple list of values, but an nested associative array $list=$qbList->getQuery()->getScalarResult(); // get rid of the nested array from ScalarResult $rawlist=array(); foreach ($list as $keyword=>$value) { // entity id's have to figure as keyword as array_rand() will pick only keywords - not values $id=$value['id']; $rawlist[$id]=null; } $total=min($nbSlotsOnPage,count($rawlist)); // pick only a few (ie$total) $keylist=array_rand($rawlist,$total); $qb=$this->createQueryBuilder('aw'); foreach ($keylist as $keyword=>$value) { $qb ->setParameter('keyword'.$keyword,$value) ->orWhere('aw.id = :keyword'.$keyword) ; } $result=$qb->getQuery()->getResult(); // if mixing the results is also required (could also be done by orderby rand(); shuffle($result); return $result; } 

Надеюсь, это поможет другим:

  $limit = $editForm->get('numberOfQuestions')->getData(); $sql = "Select * from question order by RAND() limit $limit"; $statement = $em->getConnection()->prepare($sql); $statement->execute(); $questions = $statement->fetchAll(); 

Обратите внимание, что этот вопрос таблицы представляет собой объект AppBundle: Question Entity. Соответственно измените данные. Количество вопросов берется из формы редактирования, обязательно проверяйте переменную для построителя форм и используйте соответственно.

Я знаю, что это старый вопрос. Но я использовал следующее решение для получения случайной строки.

Использование метода EntityRepository :

 public function findOneRandom() { $id_limits = $this->createQueryBuilder('entity') ->select('MIN(entity.id)', 'MAX(entity.id)') ->getQuery() ->getOneOrNullResult(); $random_possible_id = rand($id_limits[1], $id_limits[2]); return $this->createQueryBuilder('entity') ->where('entity.id >= :random_id') ->setParameter('random_id', $random_possible_id) ->setMaxResults(1) ->getQuery() ->getOneOrNullResult(); } 

Просто добавьте следующее:

 ->orderBy('RAND()')