symfony 按分类原则查找最新植物

ffscu2ro  于 2023-02-24  发布在  其他
关注(0)|答案(2)|浏览(139)

如何按类别获取最新的植物,多对多的关系,使用主义可以帮助我我很纠结
实体工厂

实体工厂_类别

实体类别

$sql = "SELECT category_id, c.name, c.slug, i.name
FROM category AS c
LEFT JOIN plant_category AS pc
ON pc.category_id = c.id
INNER JOIN (SELECT id, name FROM plant
ORDER BY id DESC LIMIT 1) AS i
ON pc.plant_id = i.id
GROUP BY c.id, c.id, i.name
ORDER BY c.id ASC";

我做了搜索,但我没有找到任何与教义

$t = $this->createQueryBuilder("c")
->select("c")
->from(Plant::class, "p")
->leftJoin('p.categories', 'cc')
->leftJoin('(SELECT id, name FROM plant
ORDER BY id DESC LIMIT 1) 
ON pc.plant_id = i.id', "i");
egmofgnx

egmofgnx1#

Doctrine ORM的工作方式与使用标准SQL查询稍有不同。
为了使用实体,关注点的分离从抽象(非确定性数组)变为静态模型(确定性对象),因为Category实体需要与查询的i.name列关联,以获得所需的最终结果,否则将涉及partial object,这是非常不建议的,因为它会导致实体的无效状态。
您正在尝试解决一个特殊情况,即您希望显示Category::$plants集合的ManyToMany关联中的单个特定记录,这违反了对象模型设计模式。对象模型应始终有效,因此从ORM上下文考虑这些特殊情况会破坏该核心原则。
简而言之,ORM不应该这样做,您最有可能查找数组结果(如@JeanCapelle的答案所示)或本地查询。

对象模型上的条件

最简单的解决方法是使用对象模型,并将条件应用于集合以筛选结果并获得所需的结果。但是,也非常不建议在模型上使用条件,因为这会严重影响性能,并可能导致无效的实体状态。

use Doctrine\Common\Collections\Criteria;

class Category
{
    /**
     * @return Collection|Plants[]
     */
    private $plants;

    public function __construct()
    {
        // ...
        $this->plants = new ArrayCollection();
    }

    public function getPlants(): Collection
    {
        return $this->plants;
    }

    public function getLatestPlant(): ?Plant
    {
        $criteria = Criteria::create()->setMaxResults(1);

        return $this->plants->matching($criteria->orderBy(['id', 'DESC']))->first() ? : null;
    }
}

则查询将更改为以下内容。

$qb = $this->_em->createQueryBuilder();
$t = $qb->select('c')
    ->from(Category::class, 'c')
    ->addSelect('p')
    ->leftJoin('c.plants', 'p')
    ->orderBy('c.id', 'ASC');

$categories = $t->getQuery()->getResult();

foreach ($categories as $category) {
    $latestPlant = $category->getLatestPlant();
    echo $latestPlant->getName();
}

最新的对象模型关联

被认为是最佳实践的更有利的解决方案是将外键关联添加到Category表,并在Category实体上添加ManyToOne关系,而不是依赖于子查询来从关联中筛选。其中,最新的工厂在应用程序和对象模型生命周期中进行维护。
类别表:id, name, description, slug, latest_plant

class Category
{

    /**
     * @return Collection|Plants[]
     */
    private $plants;

    /**
     * @return null|Plant
     * @ORM\ManyToOne(targetEntity=Plant::class)
     * @ORM\JoinColumn(name="latest_plant", referencedColumnName="id", nullable=true)
     */
    private ?Plant $latestPlant = null;

    public function getPlants(): Collection
    {
        return $this->plants;
    }

    // simple example on how to maintain relationship
    public function addPlant(Plant $plant)
    {
        if (!$this->plants->contains($plant)) {
            $this->plants->add($plant);
            $plant->addCategory($this);
            $this->setLatestPlant($this->plants->last() ?: null);
        }
    }

    // simple example on how to maintain relationship
    public function removePlant(Plant $plant)
    {
        if ($this->plants->contains($plant)) {
            $this->plants->removeElement($plant);
            $plant->removeCategory($this);
            if ($this->latestPlant && $this->latestPlant->getId() === $plant->getId()) {
                $this->setLatestPlant($this->plants->last() ?: null);
            }
        }
    }

    public function getLatestPlant(): ?Plant
    {
        return $this->latestPlant;
    }

    public function setLatestPlant(?Plant $plant)
    {
        $this->latestPlant = $plant;
    }
}

那么查询将如下所示。

$qb = $this->_em->createQueryBuilder();
$t = $qb->select('c')
    ->from(Category::class, 'c')
    ->addSelect('lp')
    ->leftJoin('c.latestPlant', 'lp') // Category::$latestPlant
    ->orderBy('c.id', 'ASC');

$categories = $t->getQuery()->getResult();

foreach ($categories as $category) {
    $latestPlant = $category->getLatestPlant();
    echo $latestPlant->getName();
}
5kgi1eie

5kgi1eie2#

如果您的SQL查询是您所期望的,我建议您尝试类似的东西:

$qb->select('c.id AS category_id', 'c.name', 'c.slug', 'i.name')
   ->from('Category', 'c')
   ->leftJoin('c.plantCategories', 'pc')
   ->innerJoin(
       '(SELECT p.id, p.name FROM Plant p ORDER BY p.id DESC LIMIT 1)', 
       'i', 
       Join::WITH, 
       'pc.plant = i.id'
   )
   ->groupBy('c.id', 'c.name', 'c.slug', 'i.name')
   ->orderBy('c.id', 'ASC');

$results = $qb->getQuery()->getResult();

相关问题