【问题标题】:Laravel Factory: Manual Increment of ColumnLaravel Factory:列的手动增量
【发布时间】:2017-12-12 12:20:42
【问题描述】:

对于下面的工厂定义,order 列需要是连续的。已经有一个自动递增的列id。第一行的order 应该从1 开始,每一行的order 应该是下一个数字(123 等)

$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
    return [
        'user_id' => App\User::inRandomOrder()->first()->id,
        'command' => $faker->word,
        'content' => $faker->sentence,
        'order'   => (App\AliasCommand::count()) ?
            App\AliasCommand::orderBy('order', 'desc')->first()->order + 1 : 1
    ];
});

它应该将order 列设置为比前一行多1,但是,这会导致所有行都被分配1

【问题讨论】:

  • 您是否可以为订单字段获取重复值?您拥有的这种解决方案不会阻止竞争条件。

标签: php laravel laravel-5.4 laravel-seeding


【解决方案1】:

该解决方案还解决了表格上已有数据条件:

class UserFactory extends Factory
{
    /**
     * @var string
     */
    protected $model = User::class;

    /**
     * @var int
     */
    protected static int $id = 0;

    /**
     * @return array
     */
    public function definition()
    {
        if ( self::$id == 0 ) {
            self::$id = User::query()->max("id") ?? 0;
            // Initialize the id from database if exists.
            // If conditions is necessary otherwise it would return same max id.
        }

        self::$id++;

        return [
            "id"        => self::$id,
            "email"      => $this->faker->email,
        ];
    }
}

【讨论】:

    【解决方案2】:

    这里有一些可行的方法。

    $factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
        static $order = 1;   
        return [
            'user_id' => App\User::inRandomOrder()->first()->id,
            'command' => $faker->word,
            'content' => $faker->sentence,
            'order'   => $order++
        ];
    });
    

    它只是在该函数内部保留一个计数器。

    更新:

    Laravel 8 引入了新的工厂类,所以这个请求变成:

    class AliasCommandFactory extends Factory {
    
        private static $order = 1;
    
        protected $model = AliasCommand::class;
    
        public function definition() {
             $faker = $this->faker;
             return [
                'user_id' => User::inRandomOrder()->first()->id,
                'command' => $faker->word,
                'content' => $faker->sentence,
                'order'   => self::$order++
            ];
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您确定工厂模型生成只会按顺序运行并且您不关心预先存在的数据,那么@apokryfos 的回答是一个很好的解决方案。

      但是,例如,如果您想要生成模型以插入到您的测试数据库中,其中一些记录已经存在,这可能会导致不正确的 order 值。

      对列值使用闭​​包,我们可以更好地自动化顺序。

      $factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
          return [
              'user_id' => App\User::inRandomOrder()->first()->id,
              'command' => $faker->word,
              'content' => $faker->sentence,
              'order'   => function() {
                  $max = App\AliasCommand::max('order'); // returns 0 if no records exist.
      
                  return $max+1;
              }
          ];
      });
      

      您在示例中几乎是正确的,问题是您在定义工厂时运行的是order 值执行,而不是执行上述代码的在生成单个模型时

      根据同样的原则,您还应该将user_id 代码包含在一个闭包中,否则您工厂生成的所有模型都将具有相同的用户 ID。

      【讨论】:

        【解决方案4】:

        要实现真正的自动增量,不如使用这种方法:

           $__count = App\AliasCommand::count();
           $__lastid = $__count ? App\AliasCommand::orderBy('order', 'desc')->first()->id : 0 ;
        
        
           $factory->define(App\AliasCommand::class,
               function(Faker\Generator $faker) use($__lastid){
        
               return [
        
                 'user_id' => App\User::inRandomOrder()->first()->id,
                 'command' => $faker->word,
                 'content' => $faker->sentence,
                 'order'   => $faker->unique()->numberBetween($min=$__lastid+1, $max=$__lastid+25),
        
                 /*  +25 (for example here) is the number of records you want to insert 
                     per run.
                     You can set this value in a config file and get it from there
                     for both Seeder and Factory ( i.e here ).
                 */
              ];
        
           });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-07-01
          • 2020-11-16
          • 1970-01-01
          • 2019-05-16
          • 2018-04-11
          • 2020-06-10
          • 2014-05-01
          • 1970-01-01
          相关资源
          最近更新 更多