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

Laravel电商系统多类型商品的数据库继承式设计方案咨询

Laravel 电商多类型商品数据库设计最优方案

针对你遇到的「按ID搜索商品需指定类型」的问题,最适合的方案是单表继承(Single Table Inheritance),结合Laravel Eloquent的模型继承能力,既能统一存储所有商品的共同属性,又能优雅处理各类型的自定义属性,同时无需额外传入类型即可通过ID查询商品。

一、数据库表设计

方案1:字段平铺式单表(适合属性固定的场景)

创建一张products表,包含所有商品的共同属性,再为各类型商品的自定义属性添加可空字段,同时用type字段区分商品类型:

// 生成迁移文件:php artisan make:migration create_products_table
Schema::create('products', function (Blueprint $table) {
    $table->id();
    // 共同属性
    $table->string('name');
    $table->text('description');
    $table->decimal('price', 8, 2);
    $table->integer('stock')->default(0);
    $table->string('sku')->unique();
    // 商品类型标识(如cpu/gpu/keyboard/mouse)
    $table->string('type');
    // 各类型自定义属性(允许为空)
    $table->string('cpu_model')->nullable();
    $table->integer('core_count')->nullable();
    $table->string('gpu_memory')->nullable();
    $table->string('keyboard_switch')->nullable();
    $table->integer('mouse_dpi')->nullable();
    
    $table->timestamps();
});

方案2:JSON字段存储自定义属性(适合属性多变的场景)

如果各商品类型的自定义属性频繁变动,可将自定义属性存入JSON字段,减少表字段数量:

Schema::create('products', function (Blueprint $table) {
    $table->id();
    // 共同属性
    $table->string('name');
    $table->text('description');
    $table->decimal('price', 8, 2);
    $table->integer('stock')->default(0);
    $table->string('sku')->unique();
    $table->string('type');
    // 用JSON存储自定义属性
    $table->json('attributes')->nullable();
    
    $table->timestamps();
});

二、Eloquent模型实现

1. 基类Product模型

创建基类模型,通过全局作用域自动区分商品类型,并实现「根据ID自动返回对应类型模型」的逻辑:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [
        'name', 'description', 'price', 'stock', 'sku', 'type',
        // 方案1需添加自定义属性字段,方案2替换为'attributes'
        'cpu_model', 'core_count', 'gpu_memory', 'keyboard_switch', 'mouse_dpi'
    ];

    // 方案2需添加JSON字段转换
    // protected $casts = ['attributes' => 'array'];

    // 全局作用域:子模型自动筛选对应类型的数据
    protected static function booted()
    {
        static::addGlobalScope('type', function ($query) {
            if (get_called_class() !== self::class) {
                $type = strtolower(class_basename(static::class));
                $query->where('type', $type);
            }
        });
    }

    // 根据ID自动返回对应类型的模型实例
    public static function findById($id)
    {
        $product = self::find($id);
        if (!$product) {
            return null;
        }

        $modelClass = 'App\\Models\\' . ucfirst($product->type);
        return class_exists($modelClass) ? $modelClass::find($id) : $product;
    }
}

2. 子类型模型

为每种商品类型创建继承自Product的子模型,可添加专属方法或访问器:

// app/Models/Mouse.php
namespace App\Models;

class Mouse extends Product
{
    // 方案2可添加DPI访问器
    // public function getDpiAttribute()
    // {
    //     return $this->attributes['dpi'] ?? 1000;
    // }

    // 专属业务方法
    public function isHighPrecision()
    {
        return $this->mouse_dpi > 8000; // 方案1
        // return $this->dpi > 8000; // 方案2
    }
}

三、使用示例

  • 查询商品:无需传入类型,直接用基类方法即可返回对应类型的模型
// 根据ID查询,自动返回Mouse/Keyboard等子模型实例
$product = Product::findById(1);
// 调用子模型专属方法
if ($product instanceof Mouse) {
    $product->isHighPrecision();
}
  • 创建商品:直接用子模型创建,自动设置type字段
Mouse::create([
    'name' => '游戏鼠标',
    'description' => '高DPI电竞鼠标',
    'price' => 299.99,
    'stock' => 100,
    'sku' => 'MOUSE-001',
    'mouse_dpi' => 12000, // 方案1
    // 'attributes' => ['dpi' => 12000], // 方案2
]);

四、方案优势

  1. 无需指定类型查询:通过基类的findById方法,仅需ID即可获取对应类型的商品实例
  2. 代码复用性高:共同属性逻辑在基类实现,子模型专注处理专属业务
  3. 查询效率优:单表查询避免多表关联的性能损耗,JSON字段也支持Laravel的查询构造器直接筛选
  4. 扩展性强:新增商品类型仅需创建子模型,无需修改数据库结构(方案2更灵活)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 12:12:16