Вот как я запрашиваю свою базу данных для некоторых слов
$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 не желает выполнять эту функцию .
Есть несколько решений вашей проблемы, каждая из которых имеет свои недостатки:
WHERE x.id IN(?)
Для загрузки связанных объектов, передав массив идентификаторов в качестве параметра. 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()')