You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让IN在EasyAdmin EntityFilter中实现AND逻辑而非OR

解决EasyAdmin中多实体筛选的AND逻辑需求

要实现筛选同时拥有多个指定活动的人员,默认的EntityFilter用的是OR逻辑(匹配任意一个选中活动就会返回),所以需要自定义Filter来实现AND逻辑。下面提供两种可行方案:

方案一:基于EXISTS子查询的自定义Filter

这种方式对每个选中的活动单独添加存在性检查,确保用户同时关联所有选中项。

1. 创建自定义Filter类

<?php

namespace App\Filter;

use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FilterDataDto;

class EntityAndFilter extends EntityFilter
{
    protected function buildQuery(QueryBuilder $queryBuilder, FilterDataDto $filterDataDto, ?FieldDto $fieldDto, EntityDto $entityDto): void
    {
        $selectedEntities = $filterDataDto->getValue();
        if (empty($selectedEntities)) {
            return;
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $associationField = $fieldDto->getProperty();

        // 对每个选中的活动,添加独立的EXISTS子查询
        foreach ($selectedEntities as $index => $activity) {
            $subAlias = 'activity_sub_' . $index;
            $queryBuilder
                ->andWhere(sprintf('EXISTS (SELECT 1 FROM %s.%s %s WHERE %s.id = :activity_id_%d)', $rootAlias, $associationField, $subAlias, $subAlias, $index))
                ->setParameter('activity_id_' . $index, $activity->getId());
        }
    }
}

2. 在CrudController中使用自定义Filter

use App\Filter\EntityAndFilter;
use App\Entity\Activity;

// ...

public function configureFilters(Filters $filters): Filters
{
    return $filters
        ->add(EntityAndFilter::new('activities', 'Activités')
            ->setFormTypeOptions([
                'class' => Activity::class,
                'multiple' => true,
                'choice_label' => 'name', // 替换为你的Activity实体显示字段
            ]));
}

方案二:基于GROUP BY + COUNT的筛选逻辑

这种方式通过分组统计用户关联的活动数量,确保数量等于选中的活动总数,从而实现“同时拥有所有选中项”的效果。

修改自定义Filter的buildQuery方法

protected function buildQuery(QueryBuilder $queryBuilder, FilterDataDto $filterDataDto, ?FieldDto $fieldDto, EntityDto $entityDto): void
{
    $selectedEntities = $filterDataDto->getValue();
    if (empty($selectedEntities)) {
        return;
    }

    $rootAlias = $queryBuilder->getRootAliases()[0];
    $associationField = $fieldDto->getProperty();
    $selectedActivityIds = array_map(fn($activity) => $activity->getId(), $selectedEntities);
    $requiredCount = count($selectedActivityIds);

    $queryBuilder
        ->innerJoin(sprintf('%s.%s', $rootAlias, $associationField), 'a')
        ->where('a.id IN (:selected_activity_ids)')
        ->setParameter('selected_activity_ids', $selectedActivityIds)
        ->groupBy(sprintf('%s.id', $rootAlias))
        ->having(sprintf('COUNT(DISTINCT a.id) = %d', $requiredCount));
}

原理说明

默认的EntityFilter内部使用OrX组合条件,所以选中多个值时会返回匹配任意一个的结果。而上述两种方案:

  • 方案一通过多个EXISTS子查询的AND组合,确保用户同时关联所有选中的活动;
  • 方案二通过分组计数,验证用户关联的活动包含所有选中项(去重计数等于选中数量)。

两种方案都能精准筛选出同时拥有“illustrateur/dessinateur”和“Animateur/intervenant”两个活动的人员。

内容的提问来源于stack exchange,提问作者tristan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:45:44