Laravel Eloquent:不同类型产品(书籍/电影)的数据库关联建模咨询
Laravel Eloquent 多类型产品属性建模方案
一、数据库结构设计
按照需求,需建立4张核心表:
products:存储产品基础信息
字段:id,title,description,price,product_type_id,created_at,updated_atproduct_types:存储产品类型(Book/Movie)
字段:id,name(值为book或movie),created_at,updated_atbook_product_properties:存储书籍专属属性,与products一对一关联
字段:id,product_id,author,num_of_pages,created_at,updated_atmovie_product_properties:存储电影专属属性,与products一对一关联
字段:id,product_id,director,runtime,created_at,updated_at
二、Eloquent模型定义
1. Product 模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasOne; class Product extends Model { protected $fillable = ['title', 'description', 'price', 'product_type_id']; // 关联产品类型 public function type(): BelongsTo { return $this->belongsTo(ProductType::class, 'product_type_id'); } // 关联书籍属性 public function bookProperties(): HasOne { return $this->hasOne(BookProductProperty::class); } // 关联电影属性 public function movieProperties(): HasOne { return $this->hasOne(MovieProductProperty::class); } // 自定义访问器:统一获取对应类型的属性 public function getPropertiesAttribute() { return match($this->type?->name) { 'book' => $this->bookProperties, 'movie' => $this->movieProperties, default => null, }; } // 本地作用域:按产品类型筛选 public function scopeOfType($query, string $typeName) { return $query->whereHas('type', fn($q) => $q->where('name', $typeName)); } }
2. ProductType 模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; class ProductType extends Model { protected $fillable = ['name']; public function products(): HasMany { return $this->hasMany(Product::class); } }
3. BookProductProperty 模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class BookProductProperty extends Model { protected $fillable = ['product_id', 'author', 'num_of_pages']; public function product(): BelongsTo { return $this->belongsTo(Product::class); } }
4. MovieProductProperty 模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class MovieProductProperty extends Model { protected $fillable = ['product_id', 'director', 'runtime']; public function product(): BelongsTo { return $this->belongsTo(Product::class); } }
三、便捷查询实现
1. 按类型查询产品及属性
// 查询所有书籍及属性 $books = Product::ofType('book')->with('bookProperties')->get(); // 查询所有电影及属性 $movies = Product::ofType('movie')->with('movieProperties')->get();
2. 获取全部产品并自动加载对应属性
如果需要一次性获取所有类型的产品并加载对应属性,可通过集合处理:
$allProducts = Product::with('type') ->get() ->map(function ($product) { $typeName = $product->type?->name; if ($typeName === 'book') { $product->load('bookProperties'); } elseif ($typeName === 'movie') { $product->load('movieProperties'); } return $product; }); // 直接通过访问器获取属性 foreach ($allProducts as $product) { dump($product->properties); // 自动返回书籍或电影的属性 }
3. 关联创建产品及属性
// 获取书籍类型ID $bookTypeId = ProductType::where('name', 'book')->value('id'); // 创建书籍产品并关联属性 $bookProduct = Product::create([ 'title' => 'Laravel从入门到精通', 'description' => '全面讲解Laravel框架的开发指南', 'price' => 79.9, 'product_type_id' => $bookTypeId, ]); $bookProduct->bookProperties()->create([ 'author' => '张三', 'num_of_pages' => 450, ]);
四、额外优化建议
- 在
product_type_id、book_product_properties.product_id、movie_product_properties.product_id字段上添加索引,提升关联查询速度 - 若后续新增产品类型,只需新增对应属性表及模型关联,扩展性强
- 可通过模型观察者,在创建产品时自动初始化对应属性表的空记录,避免属性查询时出现null
内容的提问来源于stack exchange,提问作者0xbee
相关产品推荐
相关产品推荐

