首页 > 解决方案 > Laravel Eloquent 3 个表 + 1 个数据透视表

问题描述

我正在设计一个数据库来管理products. 每个产品可能有多个color和多个size(例如,如果产品是 T 恤,那么同一件衬衫可以是小号、中号或大号,并且是红色、绿色或蓝色)所以我最终得到了 3 张桌子。

我需要能够存储库存中有多少具有特定尺寸和特定颜色的产品以及每种产品的价格。所以我创建了一个包含以下字段的第四个表:

我为每个表都有一个模型,并使用该belongsToMany方法定义所有表之间的关系。“问题”是它只允许指定 2 个表的外键(文档的示例是用户、角色和角色用户)。

有没有办法在 Eloquent 中定义这些表之间的这种关系?

例如,我需要能够查询数据库以获取所有可用的绿色大型产品。我知道如何使用纯 SQL 来实现这一点,但我正在寻找一个更雄辩的版本。

标签: phpmysqllaravel

解决方案


您所说的“产品”可能更好地命名为“样式”。产品表是包含数量和价格的数据透视表。是的,您有四个表:colorssizesstyles(请参阅播种机的示例),以及 color_size_style 数据透视表,我将其称为products

颜色、尺寸和样式表的迁移:

// create colors table
Schema::create('colors', function (Blueprint $table) {
    $table->id();
    $table->string('color', 100);
});

// create sizes table
Schema::create('sizes', function (Blueprint $table) {
    $table->id();
    $table->string('size', 100);
});

// create styles table
Schema::create('styles', function (Blueprint $table) {
    $table->id();
    $table->string('style', 100);
});

products 表的迁移,它是 color_size_style 三向数据透视表,带有额外的列数量和价格:

// create products table
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->foreignId('color_id')->constrained();
    $table->foreignId('size_id')->constrained();
    $table->foreignId('style_id')->constrained();
    $table->integer('quantity')->default(0);
    $table->decimal('price')->default(0.00);
});

颜色、尺寸和样式的模型

// define color model with size and style relationships
class Color extends Model
{
    public function sizes()
    {
        return $this->belongsToMany(Size::class, 'products');
    }
    public function styles()
    {
        return $this->belongsToMany(Style::class, 'products');
    }
}

// define size model with color and style relationships
class Size extends Model
{
    public function colors()
    {
        return $this->belongsToMany(Color::class, 'products');
    }
    public function styles()
    {
        return $this->belongsToMany(Style::class, 'products');
    }
}

// define style model with color and size relationships
class Style extends Model
{
    public function colors()
    {
        return $this->belongsToMany(Color::class, 'products');
    }
    public function sizes()
    {
        return $this->belongsToMany(Size::class, 'products');
    }
}

颜色、尺寸和样式的播种机:

// seed default colors
class ColorSeeder extends Seeder
{
    public function run()
    {
        $colors = [
            ['color' => 'black'],
            ['color' => 'white'],
            ['color' => 'gray'],
            ['color' => 'maroon'],
            ['color' => 'purple'],
            ['color' => 'navy'],
            ['color' => 'teal']
        ];

        DB::table('colors')->insert($colors);
    }
}

// seed default sizes
class SizeSeeder extends Seeder
{
    public function run()
    {
        $sizes = [
            ['size' => 'XS'],
            ['size' => 'S'],
            ['size' => 'M'],
            ['size' => 'L'],
            ['size' => 'XL'],
            ['size' => 'XXL']
        ];

        DB::table('sizes')->insert($sizes);
    }
}

// seed default styles
class StyleSeeder extends Seeder
{
    public function run()
    {
        $styles = [
            ['style' => 'Unisex Short Sleeve T-Shirt'],
            ['style' => 'Unisex Tank Top'],
            ['style' => 'Unisex Pullover Hoodie'],
            ['style' => 'Women\'s Short Sleeve T-Shirt'],
            ['style' => 'Women\'s Flowy Long Sleeve Shirt'],
            ['style' => 'Men\'s Polo Shirt']
        ];

        DB::table('styles')->insert($styles);
    }
}

现在您可以在 products 表中添加一个条目:

$color = Color::inRandomOrder()->first();
$size = Size::inRandomOrder()->first();
$style = Style::inRandomOrder()->first();

$color->sizes()->attach($size, ['style_id' => $style->id]);

// or in any other combination:
// $color->styles()->attach($style, ['size_id' => $size->id]);
// $size->colors()->attach($color, ['style_id' => $style->id]);
// $size->styles()->attach($style, ['color_id' => $color->id]);
// $style->colors()->attach($color, ['size_id' => $size->id]);
// $style->sizes()->attach($size, ['color_id' => $color->id]);

要获得所有可能的组合(不是我们想要的):

select colors.color,sizes.size,styles.style from colors join sizes join styles;

要获得我们标记为存在的产品:

select products.id,products.quantity,styles.style,sizes.size,colors.color,products.price
from products
join colors on colors.id=products.color_id
join sizes on sizes.id=products.size_id
join styles on styles.id=products.style_id
order by style,size,color;

虽然技术上没有必要,但您可能还需要一个产品模型。或者也许一个控制器就足够了——我不确定。但这应该足以让您了解三向枢轴概念。;)


推荐阅读