实现Laravel Eloquent模型继承:多类型车辆数据架构方案咨询
嘿,针对你要扩展车型存储的问题,我来拆解下几种可行方案的优劣,以及最适合你的实现方式~
方案1:单表继承(你之前尝试的方式)
这是最直接的方案,但你遇到的fillable问题其实是可以解决的,先说说它的优缺点:
- 优点:查询不用关联,操作简单,适合数据量不大、车型变动少的场景
- 缺点:字段冗余(很多车型用不到的字段会留空),后期扩展新车型需要加字段,不够灵活
优化fillable的实现方式
你可以在父模型定义公共可填充字段,子模型里追加专属字段,比如:
// 父模型 app/Models/Vehicle.php class Vehicle extends Model { protected $fillable = ['manufacturer_id', 'mileage', 'type']; } // 子模型 app/Models/Bike.php class Bike extends Vehicle { protected $fillable = ['cylinder_capacity', 'seats']; public function __construct(array $attributes = []) { parent::__construct($attributes); // 合并父模型和子模型的fillable $this->fillable = array_merge(parent::$fillable, $this->fillable); } // 全局作用域,确保查询Bike时只返回type为bike的记录 protected static function booted() { static::addGlobalScope('bike_type', function ($query) { $query->where('type', 'bike'); }); } } // Car和Truck模型同理,只需修改fillable和全局作用域的type值
方案2:多态关联(推荐长期使用的方案)
这是Laravel Eloquent中处理这类"公共属性+专属属性"场景的规范方案,结构更清晰,扩展性更强。
数据库表设计
首先需要创建4张表:
vehicles:存储所有车型的公共字段Schema::create('vehicles', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('manufacturer_id'); $table->integer('mileage'); // 多态关联字段 $table->string('vehicleable_type'); $table->unsignedBigInteger('vehicleable_id'); $table->timestamps(); });bikes:存储摩托车的专属字段Schema::create('bikes', function (Blueprint $table) { $table->id(); $table->integer('cylinder_capacity'); $table->integer('seats'); $table->timestamps(); });cars:存储轿车的专属字段Schema::create('cars', function (Blueprint $table) { $table->id(); $table->integer('doors'); $table->timestamps(); });trucks:存储卡车的专属字段(示例加了load_capacity)Schema::create('trucks', function (Blueprint $table) { $table->id(); $table->decimal('load_capacity', 8, 2); $table->timestamps(); });
模型关联实现
// app/Models/Vehicle.php class Vehicle extends Model { protected $fillable = ['manufacturer_id', 'mileage']; // 定义多态关联 public function vehicleable() { return $this->morphTo(); } } // app/Models/Bike.php class Bike extends Model { protected $fillable = ['cylinder_capacity', 'seats']; // 关联到公共的Vehicle模型 public function vehicle() { return $this->morphOne(Vehicle::class, 'vehicleable'); } } // app/Models/Car.php class Car extends Model { protected $fillable = ['doors']; public function vehicle() { return $this->morphOne(Vehicle::class, 'vehicleable'); } } // app/Models/Truck.php同理
使用示例
创建一辆带公共信息的摩托车:
// 先创建摩托车专属信息 $bike = Bike::create([ 'cylinder_capacity' => 250, 'seats' => 2 ]); // 关联创建公共车辆信息 $bike->vehicle()->create([ 'manufacturer_id' => 1, 'mileage' => 5000 ]); // 查询摩托车及其公共信息 $bikeWithVehicle = Bike::with('vehicle')->find(1); echo $bikeWithVehicle->vehicle->mileage; // 输出5000
方案对比与最优选择
- 如果你的业务车型固定、数据量极大且查询性能优先,可以用优化后的单表继承方案
- 如果你的业务需要频繁扩展车型、重视数据结构整洁性和可维护性,多态关联是最优选择——它完全避免了字段冗余,每个车型的专属字段独立管理,后续加新车型只需新增表和模型,不用修改原有结构
内容的提问来源于stack exchange,提问作者Bruno Rodrigues
相关产品推荐
相关产品推荐

