【发布时间】:2016-01-15 09:19:39
【问题描述】:
大家好,当我使用自定义 DQL 从存储库获取时,我有两个对象 Point 和 Subpoint。我想按字段顺序对点进行排序,将子点按字段排序。
这里是实体:
namespace George\ArchitectureBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model\Translatable\Translatable;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\File;
/**
* Point
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="George\ArchitectureBundle\Entity\PointRepository")
* @Vich\Uploadable
*/
class Point
{
use Translatable;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var Object
* @Gedmo\SortableGroup
* @ORM\ManyToOne(targetEntity="George\ObjectsBundle\Entity\Object", inversedBy="architecturespoints")
* @ORM\JoinColumn(name="object_id", referencedColumnName="id")
*/
private $object;
/**
* @ORM\OneToMany(targetEntity="George\ArchitectureBundle\Entity\Subpoint", mappedBy="point")
*/
private $subpoints;
/**
* @var integer
* @Gedmo\SortablePosition
* @ORM\Column(name="ord", type="integer")
*/
private $ord;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="update")
* @ORM\Column(name="updated", type="datetime")
*/
private $updated;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="create")
* @ORM\Column(name="created", type="datetime")
*/
private $created;
public function __construct()
{
$this->subpoints = new ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @return Object
*/
public function getObject()
{
return $this->object;
}
/**
* @param Object $object
*/
public function setObject($object)
{
$this->object = $object;
}
/**
* @return int
*/
public function getOrd()
{
return $this->ord;
}
/**
* @param int $ord
*/
public function setOrd($ord)
{
$this->ord = $ord;
}
/**
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* @return mixed
*/
public function getSubpoints()
{
return $this->subpoints;
}
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Vich\UploadableField(mapping="point_image", fileNameProperty="imageName")
*
* @var File
*/
private $imageFile;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @var string
*/
private $imageName;
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
// $this->setModefied(new \DateTime('now')) ;
}
}
/**
* @return File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* @param string $imageName
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
}
/**
* @return string
*/
public function getImageName()
{
return $this->imageName;
}
}
子点:
namespace George\ArchitectureBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Knp\DoctrineBehaviors\Model\Translatable\Translatable;
use Gedmo\Mapping\Annotation as Gedmo;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\File;
/**
* Subpoint
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="George\ArchitectureBundle\Entity\SubpointRepository")
* @Vich\Uploadable
*/
class Subpoint
{
use Translatable;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var Points
* @Gedmo\SortableGroup
* @ORM\ManyToOne(targetEntity="George\ArchitectureBundle\Entity\Point", inversedBy="subpoints")
*/
private $point;
/**
* @var integer
* @Gedmo\SortablePosition
* @ORM\Column(name="ord", type="integer")
*/
private $ord;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="update")
* @ORM\Column(name="updated", type="datetime")
*/
private $updated;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="create")
* @ORM\Column(name="created", type="datetime")
*/
private $created;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @return Points
*/
public function getPoint()
{
return $this->point;
}
/**
* @param Points $point
*/
public function setPoint($point)
{
$this->point = $point;
}
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Vich\UploadableField(mapping="point_image", fileNameProperty="imageName")
*
* @var File
*/
private $imageFile;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @var string
*/
private $imageName;
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
// $this->setModefied(new \DateTime('now')) ;
}
}
/**
* @return File
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* @param string $imageName
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
}
/**
* @return string
*/
public function getImageName()
{
return $this->imageName;
}
/**
* @return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* @return int
*/
public function getOrd()
{
return $this->ord;
}
/**
* @param int $ord
*/
public function setOrd($ord)
{
$this->ord = $ord;
}
}
存储库点,当我得到要由 ord 排序的点和要由 ord 排序的子点时,我想在这里:
namespace George\ArchitectureBundle\Entity;
/**
* PointRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class PointRepository extends \Doctrine\ORM\EntityRepository
{
public function getPointsByObject($object)
{
$em = $this->getEntityManager();
$query = $em->createQuery("SELECT p FROM George\ArchitectureBundle\Entity\Point p WHERE p.object =".$object." ORDER BY p.ord ASC");
return $query->getResult();
}
}
但是当我将 creatQuery 放入点存储库时
"SELECT p FROM George\ArchitectureBundle\Entity\Point p WHERE p.object =".$object." ORDER BY p.ord ASC, p.subpoints.ord ASC "
我收到错误:
[Semantical Error] line 0, col 107 near 'ord ASC ': Error: Class George\ArchitectureBundle\Entity\Point has no field or association named subpoints.ord
编辑 问题的解决方案是在@Yoshi 和@Veve 的指导下使用查询生成器:
public function getPointsByObject($object)
{
$em = $this->getEntityManager();
// $query = $em->createQuery("SELECT p FROM George\ArchitectureBundle\Entity\Point p left join George\ArchitectureBundle\Entity\Subpoint s WITH s.point = p WHERE p.object =".$object." ORDER BY p.ord ASC, s.ord ASC");
$qb = $em->createQueryBuilder();
$qb->select('p')
->from('George\ArchitectureBundle\Entity\Point','p')
->where(' p.object =:object')
->leftJoin('George\ArchitectureBundle\Entity\Subpoint', 's', 'WITH', 's.point = p')
->orderBy('p.ord','ASC')
->orderBy('s.ord','ASC');
$qb->setParameters(array(
'object' => $object
));
$query= $qb->getQuery();
return $query->getResult();
}
【问题讨论】:
-
您有什么充分的理由使用教义并仍然手动构建查询字符串?这里有严重问题。使用
setParameter或类似名称。 -
您对参数的看法是对的,但问题出在订单语句上,它在第二个订单中,而不是在参数对象中。
-
我的意思是,当您正确构建查询时,您肯定会更轻松地解决订单问题。例如。使用查询生成器,您可以根据需要多次添加
addOrderBy()。也就是说,也许添加 renderd dql,这样我们就可以看到它而无需猜测$object可能会做什么。 -
你说得对,我会重建它并编辑帖子。
-
但我可能对这个问题有所猜测。我认为您不能像您那样直接按关系订购。我认为您必须添加一个带有别名的连接,并将此别名 +
.ord用于第二个顺序子句。
标签: symfony doctrine-orm dql