【问题标题】:Laravel Nova sorting oneToMany shows dupplicatesLaravel Nova 排序一对多显示重复
【发布时间】:2021-12-12 00:26:28
【问题描述】:

当我对我的相关实体进行排序时,我会得到重复的值,当被排序的列中有空值或相同的值时。

问题出现在关系的索引页面中,当我点击“下一步”时:在关系的下 5 个结果中,有前 5 个结果中已经存在的结果。分页好像坏了。

例如,如果我尝试对“应用程序总数”列进行排序,并且在结果集中对应的字段applies 中有null 值,那么当我单击时,我会在后续页面上得到重复的结果在“下一步”上。

其他示例:我尝试对“未发布时间”列进行排序,并且有许多值具有完全相同的unpublished_at 日期。然后我在下一页上得到重复的结果。

在我看来,当被排序的列没有差异时,Nova 无法正确处理逻辑“排序/分页”。在这种情况下,它应该按另一列排序,比如说我认为的 ID,它始终是唯一的。

编辑:我想补充一点,JobOnJobboard 基于具有其他有意义的域信息的数据透视表('instances_offers')。但我将Job 链接到它作为一个简单的HasMany 关系(而不是BelongsToMany 关系),因为我不需要访问多对多关系的另一端。我只需要数据透视表上的信息。

有什么想法吗?

在这张图片中,左侧突出显示的一些 ID 也会出现在接下来的 5 个结果中,这非常令人困惑:


Laravel 6.17.1
新星 2.12

App\Job => 相关实体

App\JobOnJobboard => 关系


App\Nova\Job

class Job extends Resource
{
    /**
     * The model the resource corresponds to.
     *
     * @var string
     */
    public static $model = 'App\Job';

    /**
     * The single value that should be used to represent the resource when being displayed.
     *
     * @var string
     */
    public static $title = 'title';

    /**
     * The per-page options used the resource index.
     *
     * @var array
     */
    public static $perPageOptions = [10, 20, 25];

    public function fields(Request $request): array
    {
        return [
            HasMany::make('JobOnJobboard')
                ->hideFromIndex(),
        ];
    }
}

App\Nova\JobOnJobboard

class JobOnJobboard extends Resource
{
    /**
     * The model the resource corresponds to.
     *
     * @var string
     */
    public static $model = 'App\JobOnJobboard';

    /**
     * The columns that should be searched.
     *
     * @var array
     */
    public static $search = [
        'id',
    ];
    public static $title = 'id';


    /**
     * Get the fields displayed by the resource.
     *
     * @return array
     */
    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),
            Text::make('Hits', 'hit')->readonly(true)->sortable(),
            Text::make('Total applications', 'applies')->readonly(true)->sortable(),
            Text::make('Status')->readonly(true)->sortable(),
            DateTime::make('Published At')
                ->readonly(true),
            DateTime::make('Unpublished At')
                ->readonly(true),
        ];
    }
}

App\Job


class Job extends Model
{
    use SoftDeletes;
    use Filterable;
    use HasJsonRelationships;

    protected $table = 'offers';

    protected $dates = [
        'created_at',
        'updated_at',
        'archived_at',
        'published_at',
        'unpublished_at',
    ];

    protected $casts = [
        'published_at' => 'date:Y-m-d H:i:s',
        'unpublished_at' => 'date:Y-m-d',
    ];

    protected $appends = [
        'location_iso',
    ];

    public function jobOnJobboard(): HasMany
    {
        return $this->hasMany(JobOnJobboard::class, 'offer_id', 'id');
    }
}

App\JobOnJobboard

class JobOnJobboard extends Pivot
{
    /**
     * {@inheritdoc}
     */
    protected $table = 'instances_offers';

    /**
     * {@inheritdoc}
     */
    protected $dates = [
        'created_at',
        'updated_at',
        'published_at',
        'unpublished_at',
    ];

    public function job(): BelongsTo
    {
        return $this->belongsTo(Job::class, 'offer_id');
    }
}

【问题讨论】:

  • 字段ID是否自增?
  • 您好@flakerimi,谢谢您的提问。是的,表“instances_offers”的字段“ID”是自动递增的,就像表“offer”一样。你有什么想法吗?我想补充一点,JobOnJobboard 基于具有其他有意义的域信息的数据透视表('instances_offers')。但我将 Job 作为简单的 HasMany 关系(而不是 BelongsToMany 关系)链接到它。

标签: eloquent laravel-6 laravel-nova


【解决方案1】:

所以我找到了解决方案。问题是 MySQL 位置在使用 ORDER BY 时是不确定的。 “而且由于每次访问页面时都会执行新查询,因此行将被重新“打乱”。

信息来源:https://stackoverflow.com/a/27803177/10767428

由于有序列中的所有行都具有相同的值(无论是“null”还是其他值),MySQL 无法保持每个页面之间的一致性。因此重复的结果。

为了解决这个问题,按照上面的 stackoverflow 响应,我在我的 Base Nova Resource 上做了:

app/Nova/Resource.php

abstract class Resource extends NovaResource
{
    public static function indexQuery(NovaRequest $request, $query): Builder
    {
        $table = $query->getModel()->getTable();

        if (Schema::hasColumn($table, 'id')) {
            return $query->orderBy('id');
        }

        return $query;
    }

}

我只是检查我当前的模型表是否有“id”列,如果是的话,将其添加为新的订单项。

这样,如果我有相同值的行,MySQL 仍将按 ID 列对它们进行排序。


有关更多信息,该补丁之前的 sql 查询是:

select * from `instances_offers` where `instances_offers`.`offer_id` = ? and `instances_offers`.`offer_id` is not null order by `applies` asc limit 6 offset 5

补丁之后,变成:

select * from `instances_offers` where `instances_offers`.`offer_id` = ? and `instances_offers`.`offer_id` is not null order by `applies` asc, `id` asc limit 6 offset 5

注意id asc 添加了一个额外的排序层,以防止结果在下一页中被“打乱”。

【讨论】:

    猜你喜欢
    • 2021-07-16
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多