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

Shopware 6中使用Criteria过滤JSON空数据遇问题

如何用Criteria对JSON字段做空值检查?

你的问题核心是默认的existence-filter针对JSON数组字段生成的JSON_CONTAINS无法正确判断空数组或NULL的情况,以下是几种不需要写复杂装饰器的解决办法:


方法一:自定义筛选器,手动构建Criteria逻辑

放弃existence-filter,自己写一个带handler的自定义筛选器,直接在前端拼接需要的查询条件:

options['vat-id-filter'] = {
    property: 'orderCustomer.customer.vatIds',
    type: 'custom-vat-filter',
    label: this.$tc('sw-order-list.filters.vat-id.placeholder'),
    options: [
        { label: this.$tc('sw-order-list.filters.vat-id.textHasCriteria'), value: 'has' },
        { label: this.$tc('sw-order-list.filters.vat-id.textNoCriteria'), value: 'none' }
    ],
    handler: (filterValue, criteria) => {
        if (filterValue === 'has') {
            // 筛选有税号的:JSON字段非空且不是空数组
            criteria.addFilter(Criteria.not('empty', 'orderCustomer.customer.vatIds'));
            criteria.addFilter(Criteria.not('equals', 'orderCustomer.customer.vatIds', '[]'));
        } else if (filterValue === 'none') {
            // 筛选无税号的:JSON字段为NULL或空数组
            criteria.addFilter(Criteria.or([
                Criteria.empty('orderCustomer.customer.vatIds'),
                Criteria.equals('orderCustomer.customer.vatIds', '[]')
            ]));
        }
    }
};

这种方式直接绕开默认的ListField解析逻辑,完全由自己控制生成的查询条件。

方法二:给实体添加计算字段

在后端实体定义里新增一个基于JSON字段的计算字段,把“是否有税号”转成布尔值,前端直接用布尔筛选器:

后端修改(CustomerDefinition类)

protected function defineFields(): FieldCollection
{
    $fields = parent::defineFields();
    
    $fields->add(
        new JsonField('vat_ids', 'vatIds'),
        // 新增计算字段:通过JSON_LENGTH判断数组是否有内容
        new CalculatedField(
            'has_vat_id',
            'JSON_LENGTH(vat_ids) > 0',
            ['vat_ids'],
            CalculatedField::TYPE_BOOLEAN
        )
    );
    
    return $fields;
}

前端筛选器修改

options['vat-id-filter'] = {
    property: 'orderCustomer.customer.hasVatId',
    type: 'boolean-filter',
    label: this.$tc('sw-order-list.filters.vat-id.placeholder'),
    labelTrue: this.$tc('sw-order-list.filters.vat-id.textHasCriteria'),
    labelFalse: this.$tc('sw-order-list.filters.vat-id.textNoCriteria'),
};

这种方式把JSON的复杂判断转成简单的布尔值筛选,维护成本更低。

方法三:装饰SqlQueryParser(仅迫不得已时用)

如果必须保留existence-filter的原有逻辑,才需要装饰SqlQueryParser的parseEqualsFilter方法,修改ListField对应的SQL生成:

// 自定义装饰器类
class DecoratedSqlQueryParser extends SqlQueryParser
{
    protected function parseEqualsFilter(Filter $filter, QueryBuilder $query, EntityDefinition $definition, string $root): void
    {
        // 针对vatIds字段的空值判断做特殊处理
        if ($filter instanceof EqualsFilter 
            && $filter->getField() === 'vatIds' 
            && $definition instanceof CustomerDefinition
        ) {
            $column = $this->getField($definition, $filter->getField(), $root);
            
            if ($filter->getValue() === null) {
                // 空值逻辑:判断JSON_LENGTH为0或字段为NULL
                $query->andWhere($query->expr()->orX(
                    $query->expr()->isNull($column),
                    "JSON_LENGTH({$column}) = 0"
                ));
                return;
            }
        }
        
        // 其他情况走默认逻辑
        parent::parseEqualsFilter($filter, $query, $definition, $root);
    }
}

然后在services.xml里注册装饰器:

<service id="YourPlugin\Core\Framework\DataAbstractionLayer\Sql\Parser\DecoratedSqlQueryParser" 
         decorates="Shopware\Core\Framework\DataAbstractionLayer\Sql\Parser\SqlQueryParser">
    <argument type="service" id=".inner"/>
    <argument type="service" id="Shopware\Core\Framework\DataAbstractionLayer\FieldSerializer\FieldSerializerRegistry"/>
</service>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:17:39