Laravel Nova可重复组件配置错误引发SQL列不存在异常
Laravel Nova 一对多关联保存错误分析与解决
问题场景
环境:Laravel 10 / Nova 4.27
模型关联代码
ProductAttribute模型:
class ProductAttribute extends Model { protected $table = 'product_attributes'; protected $primaryKey = 'id'; protected $fillable = ['product_id', 'key', 'value' ]; public function scopeGetByProductId($query, int $productId= null) { if (!empty($productId)) { $query->where($this->table . '.product_id', $productId); } return $query; } public function product(){ return $this->belongsTo(Product::class, 'product_id','id'); } }
Product模型:
class Product extends Model implements HasMedia { use Sluggable, InteractsWithMedia; use HasHeartbeats; protected $table = 'products'; protected $primaryKey = 'id'; public function productAttributes(): HasMany { return $this->hasMany(ProductAttribute::class); } }
Nova配置操作
- 通过
php artisan nova:repeatable ProductAttribute创建可重复组件,字段配置:
class ProductAttribute extends Repeatable { public function fields(NovaRequest $request) { return [ Text::make(__('Key'))->rules('required', 'max:255'), Textarea::make('Value')->rules('required', 'max:255'), ]; } }
- 在Product的Nova资源中添加字段:
HasMany::make(name: __('Product attributes'), attribute: 'productAttributes', resource: \App\Nova\ProductAttribute::class)->fullWidth(),
错误信息
保存时出现SQL错误:
[2024-11-22 10:51:09] local.ERROR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'productAttributes' in 'field list' (Connection: mysql, SQL: update `product_attributes` set `productAttributes` = [{"type":"product-attribute","fields":{"key":"11","value":"11111"}}], `product_attributes`.`updated_at` = 2024-11-22 10:51:09 where `id` = 5) {"userId":1,"exception":"[object] (Illuminate\\Database\\QueryException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'productAttributes' in 'field list' (Connection: mysql, SQL: update `product_attributes` set `productAttributes` = [{\"type\":\"product-attribute\",\"fields\":{\"key\":\"11\",\"value\":\"11111\"}}], `product_attributes`.`updated_at` = 2024-11-22 10:51:09 where `id` = 5) at /mnt/_work_sdb8/wwwroot/lar/NovaProducts/vendor/laravel/framework/src/Illuminate/Database/Connection.php:829) [stacktrace]
错误原因
混淆了Nova Repeatable组件与Nova Resource的用途:
HasMany字段要求关联的是标准Nova Resource(对应独立的数据模型资源),但你传入的是通过nova:repeatable生成的Repeatable组件。- Nova错误地将Repeatable组件的序列化数据当作字段值,尝试更新
productAttributes列(该列在数据库中不存在),而非处理一对多关联的product_attributes表数据。
解决方案
根据需求选择以下两种方案之一:
方案1:使用HasMany关联标准Nova Resource(适合独立管理属性)
- 创建ProductAttribute的Nova Resource:
php artisan nova:resource ProductAttribute
- 修改生成的
app/Nova/ProductAttribute.php配置字段:
class ProductAttribute extends Resource { public static $model = \App\Models\ProductAttribute::class; public static $title = 'key'; public static $search = ['key', 'value']; public function fields(NovaRequest $request) { return [ ID::make()->sortable(), Text::make(__('Key'))->rules('required', 'max:255'), Textarea::make('Value')->rules('required', 'max:255'), BelongsTo::make('Product'), ]; } }
- 保持Product Nova资源中的
HasMany字段配置不变,此时Nova会正确处理一对多关联的增删改查。
方案2:使用Repeatable字段在Product页面内编辑属性(适合内嵌编辑)
- 删除Product Nova资源中的
HasMany字段,替换为Repeatable字段:
// app/Nova/Product.php use Laravel\Nova\Fields\Repeatable; use App\Nova\Repeatables\ProductAttribute; // 注意路径:nova:repeatable生成的文件默认在app/Nova/Repeatables目录下 public function fields(NovaRequest $request) { return [ // 其他现有字段... Repeatable::make(__('Product attributes'), 'productAttributes') ->repeatable(ProductAttribute::class) ->fullWidth(), ]; }
- 确保Product模型支持关联的批量赋值:
无需在$fillable中添加关联字段,Laravel会自动通过saveMany处理关联数据,若模型设置了$guarded,可改为:
// app/Models/Product.php protected $guarded = [];
关键概念区分
- HasMany字段:对应独立Nova Resource,提供关联列表、跳转编辑、批量操作,适配数据库一对多关联表结构。
- Repeatable字段:在当前资源页面内嵌可重复字段组,适合简单嵌套数据,Nova自动处理关联数据的增删(通过
saveMany)或序列化存储(若对应JSON字段)。
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

