【问题标题】:Laravel seeding - unique pairs of user and teacher IDsLaravel 播种 - 唯一的用户和教师 ID 对
【发布时间】:2016-01-30 06:55:26
【问题描述】:

我在 Laravel 5.1 中使用数据库迁移和播种。

迁移

public function up()
{
    Schema::create('teachers', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id')->unsigned();
        $table->integer('teacher_id')->unsigned();
        $table->boolean('disable')->default(0);
        $table->timestamps();

        $table->unique(['user_id', 'teacher_id']);

        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->foreign('teacher_id')->references('id')->on('users')->onDelete('cascade');
    });
}

*** user_id 和teacher_id 必须是唯一的。

模型工厂

$factory->define(App\Teacher::class, function ($faker) {
    return [
        'user_id'           => $faker->numberBetween(1, 59),
        'teacher_id'        => $faker->numberBetween(1, 59),
    ];
});

我在DatabaseSeeder.php 中设置了生产500 名教师关系的播种机: factory(App\Teacher::class, 500)->create();

但我收到了这个错误:

[PDOException] 
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '10-11' for key 'teachers_user_id_teacher_id_ 
unique'

如您所见,***(唯一属性)导致了错误。 有什么办法可以解决吗?你的想法是什么?

【问题讨论】:

  • 尝试生成 500 唯一的用户和教师 ID 对,同时允许每个用户和教师 ID 之间有一个介于 159 之间的数字,由于范围小,无疑会导致重复。 C(59,2) 给出了1711 可能的组合,对于您要生成的500 项目将有很高的重复对的机会,从而引发 "Duplicate entry" 错误。因此,最好的办法是将numberBetween 的上限增加到明显高于59 的值,或者在尝试存储新的配对之前缓存并检查以前生成的配对,以确保没有重复。
  • @Bogdan 有没有办法自定义工厂功能以防止重复?增加上限并不能解决问题。
  • 尝试将每个生成的对缓存在一个数组中,例如命名为$savedPairs,并且当每个新的$pair 生成时,使用array_search($pair, $savedPairs) 搜索该数组,并且只保存新的数据库条目,如果搜索结果为false

标签: php laravel laravel-5.1 laravel-migrations laravel-seeding


【解决方案1】:

您可以获得User 模型的集合,然后在while 循环中从该集合中的随机ID 中分配对:

$users = User::all(['id']);

while ($users->count() > 1) {
    // Get random user for a teacher, and remove from collection
    $teacher = $users->random();
    $users->pull($teacher->getKey());

    // Get random user and remove from collection
    $user = $users->random();
    $users->pull($user->getKey());

    Teacher::create([
        'user_id' => $user->getKey(),
        'teacher_id' => $teacher->getKey(),
    ]);
}

【讨论】:

    【解决方案2】:

    如果数据库中存在唯一记录,您可以抛出异常。然后在播种器类中,使用 try-catch 块,捕获异常什么都不做。如果遇到现有记录,播种应继续。

    示例:假设product_stocks 表中有 3 列,其中 product_idcolor_idsize_id 是唯一的。

    工厂类:

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        $productId = $this->faker->randomElement(Product::pluck('id')->toArray());
        $colorId = $this->faker->randomElement(Color::pluck('id')->toArray());
        $sizeId = $this->faker->randomElement(Size::pluck('id')->toArray());
    
        $exists = ProductStock::where([
            ['product_id', '=', $productId],
            ['color_id', '=', $colorId],
            ['size_id', '=', $sizeId],
        ])->exists();
    
        if ($exists) {
            throw new Exception('duplicate value');
        }
    
        return [
            'product_id' => $productId,
            'color_id' => $colorId,
            'size_id' => $sizeId,
            'stok_ready' => $this->faker->numberBetween(0, 100),
        ];
    }
    

    播种机类:

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        try {
            ProductStock::factory()
                ->count(Product::count() * rand(5, 10))
                ->create();
        } catch (Exception $e) {
            // do something
        }
    }
    

    【讨论】:

    • 虽然如果你的种子抛出QueryException,那么使用它而不是常规的Exception
    【解决方案3】:
    /**@var array $unique*/
    
    $repeatRandom =  static function () use (&$unique, &$repeatRandom) {
        $userId = User::pluck('id')->random();
        $teacherId = User::pluck('id')->random();
        $newPair = [
            $userId, $teacherId
        ];
    
        foreach ($unique as $items) {
            if (!array_diff_assoc($items, $newPair)) {
                return $repeatRandom($unique);
            }
        }
        return $newPair;
    };
    
    
    $factory->define(Teacher::class, static function (Faker $faker) use (&$unique, &$repeatRandom) {
    
        $userId = User::pluck('id')->random();
        $teacherId = User::pluck('id')->random();
    
        $newPair = [
            $userId, $teacherId
        ];
    
        if (is_array($unique)) {
            foreach ($unique as $items) {
                if (!array_diff_assoc($items, $newPair)) {
                    $newPair = $repeatRandom($unique);
                }
            }
        }
    
        $unique[]  = $newPair;
        return [
            'user_id' => $newPair[0],
            'teacher_id' => $newPair[1]
        ];  
    }
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-22
      • 1970-01-01
      • 2019-11-17
      相关资源
      最近更新 更多