Laravel - 填充多对多关系

51

我有一个users表和一个roles表,它们之间存在多对多关系。这两个表连接到一个名为role_user的联接表。

这是表格及其连接的模型。

以下是我在Laravel项目中使用的Model:

User

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}

角色

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

下面是 Laravel 项目中的 Factory 文件:

$factory->define(App\User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => $password ?: $password = bcrypt('secret'),
    ];
});

$factory->define(App\Role::class, function (Faker\Generator $faker) {
    return [
        'role' => $faker->realText($maxNbChars = 2),
        'description' => $faker->realText($maxNbChars = 20),
    ];
});

以下是 Laravel 项目中的 Seed 文件:

public function run()
{
    factory(App\User::class, 50)->create()->each(function ($u) {
        $u->roles()->save(factory(App\Role::class)->make());
    });

    factory(App\Role::class, 20)->create()->each(function ($u) {
        $u->users()->save(factory(App\User::class)->make());
    });
}

这应该会填充users表和roles表,但是我该如何填充role_user表呢?(我没有联接表的模型文件。)

我很新手,请帮忙。谢谢。

6个回答

94

在多对多关系中,您可以使用attach()sync()方法

有多种方法可以实现这一目的,以下是其中一种方法:

// Populate roles
factory(App\Role::class, 20)->create();

// Populate users
factory(App\User::class, 50)->create();

// Get all the roles attaching up to 3 random roles to each user
$roles = App\Role::all();

// Populate the pivot table
App\User::all()->each(function ($user) use ($roles) { 
    $user->roles()->attach(
        $roles->random(rand(1, 3))->pluck('id')->toArray()
    ); 
});

有人能解释一下它为什么在1到3之间进行随机选择而不是在1到20之间进行随机选择吗?(因为Roles中有20条记录,而不是3条记录) - Tharindu Sathischandra
4
也可以使用 $roles->random(rand(1, $roles->count())) 来从1到最大可用角色数量中获取随机角色。 - Othyn
6
这将会在用户身上随机添加1到3个角色。不会选择ID为1到3的角色!我猜 @peterm 想表明如何限制(最小值和最大值)你想要添加的角色数量。 - C0chett0

14

另一种方法是使用saveMany()函数

public function run()
{

   factory(App\User::class,3)->create();

   $roles = factory(App\Role::class,3)->create();

   App\User::All()->each(function ($user) use ($roles){
      $user->roles()->saveMany($roles);
   });
}

1
这将单独为每个用户附加3个新角色,这不是真正的多对多关系模型,实际上是多对一。 - Jacek Dziurdzikowski

7
一个更为简洁的方法是:在你定义了 App\User 和 App\Roles 的工厂之后,你可以这样调用 afterCreating 方法:
$factory->define(App\User::class, function ...);
$factory->define(App\Role::class, function ...);

$factory->afterCreating(App\User::class, function ($row, $faker) {
    $row->roles()->attach(rand(1,20));
});

在种子文件中,您需要先创建角色,然后再创建用户。

public function run()
{
    factory(App\Role::class, 20)->create();
    factory(App\User::class, 50)->create();
}

现在你有50个用户,每个用户都附有一个角色。

6

对于一个种子,你可以使用以下类似的内容:

   for ($i = 0; $i < 50; $i++) {
        $user = factory(App\User::class)->create();

        $role = factory(App\Role::class)->create();

        DB::table('role_user')->insert([
            'user_id' => $user->id,
            'role_id' => $role->id
        ]);
    }

通常情况下,您需要像has many through那样定义关联关系。 https://laravel.com/docs/5.4/eloquent-relationships#has-many-through

这样您就可以使用以下方法:

$user->roles()->save($role);

0
最好使用这种结构:
App\Role::factory()->count(20)->create();

// Populate users
App\User::factory()->count(50)->create();

// Getting all roles and saving them to variable is not too good idea.
// Instead, get count of rows.
$rolesCount = App\Role::count();

// Populate the pivot table
App\User::all()->each(function ($user) use ($rolesCount) { 
    $user->roles()->attach(
        App\Role::all()->random(rand(1, $rolesCount))->pluck('id')->toArray()
    );
});

将所有角色获取并保存到变量中不是一个好主意,为什么呢?因为只有20个值,这是资源的可忽略使用。此外,这整个方法在现代版本的Laravel中已经过时了;factory()助手已经不存在了。 - miken32
我们不需要将所有记录存储在变量中来对它们进行计量。相反,我们可以立即获取记录的数量。如果提问者在其他地方使用了@peterm的解决方案,他将会遇到性能问题(在这种情况下有20个值,但我认为我们应该给出通用答案)。 - Oybek Odilov

0
Laravel 9及其后续版本:
$roles = Role::factory()->count(10)->create();

$user->roles()->attach($roles);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接