我使用的是Laravel Eloquent。我有一个产品表,其中的字段包括标题、描述、价格和product_type_id作为每个产品所属的类型,因此产品类型可以是"Book"或"Movie"。一个产品只能属于一种类型。
现在图书和电影产品都需要存储不同的属性,对于图书,我需要存储'作者','num_of_pages'等,对于电影,我需要存储'导演','运行时'等。
这些不是动态属性,它们对于每个类型都是固定的,所以没有自定义字段。
我可以将所有这些"属性"作为列存储在产品表上,但这将意味着大量的空字段。理想情况下,我希望将它们存储在各自的属性表中,因此book_product_properties和movie_product_properties。因此,product和movie_product_properties或books_product_properties之间将是一对一的。
如何在Eloquent中为产品和许多不同属性表之间的关系建模?
我需要能够轻松地查询所有产品并获得那里的属性。
我尝试了EAV方法,将属性存储在键/值表中,但我一直在阅读EAV,大多数帖子都说要远离它,因为它的查询速度很慢,而且是维护的噩梦。
解决方案1:
表:
Products
id - integer
type - varchar
additional_data - json
迁移:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('type')
$table->json('additional_data')
});
模型:
class Product extends Model
{
$casts = [
'additional_data' => 'array'
];
}
解决方案2:
你可以使用One To Many (Polymorphic) https://laravel.com/docs/10.x/eloquent-relationships#one-to-many-polymorphic-relations
你的表看起来像:
Books
id - integer
title - string
Movies
id - integer
title - string
Products
id - integer
productable_id - integer
productable_type - string
迁移:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->morphs('productable') // this will create 2 fields: productable_id and productable_type;
//....
});
在你的模型中:
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsMorphTo;
class Product extends Model
{
/**
* Get the parent productable model (book or movie).
*/
public function productable(): MorphTo
{
return $this->morphTo();
}
}
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsMorphMany;
class Book extends Model
{
/**
* Get all of the book's products.
*/
public function products(): MorphMany
{
return $this->morphMany(Product::class, 'productable');
}
}
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsMorphMany;
class Movie extends Model
{
/**
* Get all of the movie's products.
*/
public function products(): MorphMany
{
return $this->morphMany(Product::class, 'productable');
}
}