query inner getrepository getdoctrine andwhere php doctrine2 dql

php - inner - getdoctrine()- getrepository



Cómo seleccionar al azar con doctrina (12)

Aquí es cómo consulto mi base de datos para algunas palabras

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

Estoy usando mysql y me gustaría obtener filas aleatorias que coincidan con los criterios, usaría ordenar por rand () en mi consulta.

Encontré esta pregunta similar , que básicamente sugiere que ORDER BY RAND no es compatible con la doctrina, en su lugar puede aleatorizar la clave principal. Sin embargo, esto no se puede hacer en mi caso porque tengo un criterio de búsqueda y una cláusula where para que no todas las claves principales satisfagan esa condición.

También encontré un fragmento de código que sugiere que use el DESPLAZAMIENTO para aleatorizar las filas de esta manera:

$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();

Estoy un poco confundido sobre si esto me ayudará a evitar la falta de soporte para el orden al azar en mi caso o no. No pude agregar compensación después de setMaxResult.

¿Alguna idea de cómo se puede lograr esto?


¿Por qué no usar repositorio?

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


De acuerdo con lo que Hassan Magdy Saad suggested , puede usar la popular biblioteca DoctrineExtensions :

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

Probado en Doctrine ORM 2.6.x-dev, puede hacer:

->orderBy(''RAND()'')


Doctrine 2 no admite ORDER BY rand (), pero encontré this artículo donde contiene correcciones para este tema.


El equipo de Doctrine no está dispuesto a implementar esta función .

Existen varias soluciones para su problema, cada una con sus propios inconvenientes:

  • Agregue una función numérica personalizada : vea esta función DQL RAND ()
    (puede ser lento si tiene muchas filas coincidentes)
  • Use una consulta nativa
    (Personalmente trato de evitar esta solución, que me pareció difícil de mantener)
  • Emita primero una consulta SQL sin procesar para obtener algunos identificadores aleatoriamente, luego use DQL WHERE x.id IN(?) Para cargar los objetos asociados, pasando la matriz de ID como un parámetro.
    Esta solución implica dos consultas separadas, pero podría ofrecer un mejor rendimiento que la primera solución (existen otras técnicas de SQL en bruto que ORDER BY RAND() , no las detallaré aquí, encontrará algunos buenos recursos en este sitio web).

Espero que esto ayude a otros:

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

Tenga en cuenta que la pregunta de la tabla es un AppBundle: Question Entity. Cambie los detalles en consecuencia. El número de preguntas se toma del formulario de edición, asegúrese de verificar la variable para el generador de formularios y usar en consecuencia.


La mezcla se puede hacer en el resultado de la consulta (matriz), pero la mezcla no se elige al azar.

Para elegir al azar de una entidad, prefiero hacer esto en PHP, lo que puede ralentizar el picking aleatorio, pero me permite mantener el control de las pruebas de lo que estoy haciendo y facilita la depuración eventual.

El siguiente ejemplo pone todos los ID de la entidad en una matriz, que luego puedo usar para "tratar al azar" en 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 (i.e.$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; }


La solución de @ Krzysztof es la mejor en mi humilde opinión, pero RAND () es muy lenta en consultas grandes, así que actualicé la solución de @Krysztof para obtener resultados menos "aleatorios", pero todavía son lo suficientemente aleatorios. Inspirado por esta respuesta https://.com/a/4329492/839434 .

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''); # sql query $sql = " SELECT * FROM {$table} WHERE id >= FLOOR(1 + RAND()*( SELECT MAX(id) FROM {$table}) ) LIMIT ? "; # make query return $this->getEntityManager() ->createNativeQuery($sql, $rsm) ->setParameter(1, $amount); } }


O podrías hacer esto ->

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

Por supuesto, esto sería muy ineficiente si tiene muchos registros, así que use con precaución.


Probablemente, la forma más fácil (pero no necesariamente la más inteligente) de obtener un resultado de un solo objeto CUANTO ANTES sería implementar esto en su clase de Repositorio:

public function findOneRandom() { $className = $this->getClassMetadata()->getName(); $counter = (int) $this->getEntityManager()->createQuery("SELECT COUNT(c) FROM {$className} c")->getSingleScalarResult(); return $this->getEntityManager() ->createQuery("SELECT ent FROM {$className} ent ORDER BY ent.id ASC") ->setMaxResults(1) ->setFirstResult(mt_rand(0, $counter - 1)) ->getSingleResult() ; }


Sé que esta es una vieja pregunta. Pero utilicé la siguiente solución para obtener la fila aleatoria.

Usando un método 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(); }


Sigue estos pasos:

Defina una nueva clase en su proyecto como:

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()''; } }

Registra la clase config.yml :

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

Úselo directamente como:

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


Solo agregue lo siguiente:

->orderBy(''RAND()'')