使用代表另一个字段 (`in`) 的值数组选择实体

Posted

技术标签:

【中文标题】使用代表另一个字段 (`in`) 的值数组选择实体【英文标题】:Select entities using an array of values that represents the another field (`in`) 【发布时间】:2022-01-22 18:31:23 【问题描述】:

首先,对不起这个神秘的标题,但我真的不知道如何写一个更清楚。

这不是关于join 的问题,而是关于将injoin 结合使用的问题。

我要说明我的情况。

我有一个array,其中包含城市名称列表:

$cities = ['new_york', 'rome', 'hong_kong'];

这些城市位于cities 表中,每个城市都有自己的 ID:

------------------
| ID | slug      |
|  1 | new_york  |
|  2 | rome      |
|  3 | hong_kong |
------------------

然后我有另一个表listings,其中包含各种场地的列表。 每个Listing 都有一个字段city,它将Listing 与它所在的City 相关联。 关系是ManyToOne:

# Listing

/**
 * @ORM\Entity(repositoryClass=ListingRepository::class)
 * @ORM\Table(name="listings", schema="app")
 */
class Listing

    /**
     * @ORM\Id
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private int $id;

    /** @ORM\Column(type="string", length=255, nullable=false) */
    private string $name;

    /** @ORM\ManyToOne(targetEntity=City::class, inversedBy="listings") */
    private City $city;

    ...

然后

# City

/**
 * @ORM\Entity(repositoryClass=CityRepository::class)
 * @ORM\Table(name="cities", schema="app")
 */
class City

    /**
     * @ORM\Id
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private int $id;

    /** @ORM\Column(type="string", length=255, nullable=false) */
    private string $name;

    /** @ORM\Column(type="string", length=255, nullable=false) */
    private string $slug;

    /** @ORM\OneToMany(targetEntity=Listing::class, mappedBy="city") */
    private Collection $listings;

    ...

我想要达到的目标

传递 City(ies) 的 slug 数组,我想选择属于每个传递的 City 的所有 Listings。

可能的解决方案

一种可能的解决方案是

    首先按数组中的 slug 选择所有城市, 获取实体列表 City 并循环获取它们的 ID 将 ID 列表传递给 ListingRepository 并使用 in

类似这样的:

# Not tested, but it should work (may require some bug fixing)

...
    /**
     * @param City[] $cities
     *
     * @return Listing[]
     */
    public function findAllByCities(array $cities):array
    
        $qb = $this->createQueryBuilder('l');
        $citiesIds = $this->getCitiesIds($cities);

        return $qb
            ->select('l')
            ->where($qb->expr()->in('l.city', ':cities'))
            ->setParameter('cities', $citiesIds, Connection::PARAM_STR_ARRAY)
            ->getQuery()
            ->getResult();
    

    /**
     * @param City[] $cities
     *
     * @return int[]
     */
    private function getCitiesIds(array $cities):array
    
        return array_map(static fn(City $city): int => $city->getId(), $cities);
    
...

这种方法的缺点是:

    我必须执行查询以获取城市列表 我必须循环每个返回的城市以获取其 ID

如果列表中的城市很多,这可能会变得很重。

问题

是否可以选择每个传递的 City 中的所有 Listings,但使用 slugs 而不是首先检索他们的 ID?

【问题讨论】:

【参考方案1】:

您只需加入关联的表即可。

public function findAllByCities(array $cities):array

    $qb = $this->createQueryBuilder('l');

    return $qb
        ->select('l')
        ->join('l.city', 'c')
        ->where($qb->expr()->in('c.slug', ':cities'))
        ->setParameter('cities', $cities, Connection::PARAM_STR_ARRAY)
        ->getQuery()
        ->getResult();

【讨论】:

以上是关于使用代表另一个字段 (`in`) 的值数组选择实体的主要内容,如果未能解决你的问题,请参考以下文章

如果另一个字段具有使用对象数组的值,则有条件地要求字段

如何根据唯一值和另一个表单中的值自动填写表单中的字段

如何获取选择选项的值,并使用它来查询数组,以填充另一个输入

从一个二维数组,创建另一个二维数组,该数组由从原始数组中随机选择的值(行之间不共享的值)组成,而不使用循环

根据另一个表的值选择表和字段

easyadmin 实体字段的动态自定义选择