Laravel : 使用模型工厂生成一对多关系
Laravel : using model factories to generate one-to-many relationships
我在使用 Laravel 中的工厂为模型生成多个一对多关系时遇到问题。工厂似乎只为每个俱乐部生成一个 ClubFixture,而他们应该为每个俱乐部生成 5 个 ClubFixture。
型号
俱乐部
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Club extends Model
{
//Table associated with the model
protected $table = 'clubs';
protected $fillable = ['name', 'league', 'age_group', 'colour', 'county', 'country'];
public function fixtures(){
return $this->hasMany('App\ClubFixture', 'club_id', 'id');
}
}
俱乐部赛程
namespace App;
use Illuminate\Database\Eloquent\Model;
class ClubFixture extends Model
{
//Table associated with the model
protected $table = 'club_fixtures';
}
模态工厂
$factory->define(App\Club::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'league' => $faker->word,
'age_group' => $faker->word,
'colour' => $faker->hexcolor,
'county' => $faker->state,
'country' => $faker->country,
'emblem' => $faker->imageUrl(80, 80),
'banner' => $faker->imageUrl,
'matches' => $faker->randomDigit,
'wins' => $faker->randomDigit,
'losses' => $faker->randomDigit,
];
});
$factory->define(App\ClubFixture::class, function (Faker\Generator $faker) {
return [
'club_id' => function () {
return factory(App\Club::class)->create()->id;
},
'opposition' => $faker->name,
'address' => $faker->address,
'datetime' => $faker->dateTimeBetween('now', '+30 weeks'),
'type' => $faker->randomElement(['home', 'away', 'none']),
];
});
数据库播种机
factory(App\Club::class, 100)->create()->each(function ($u) {
factory(App\ClubFixture::class, 5)->create();
});
预期结果:每个俱乐部应该有 5 个与之关联的 ClubFixtures
实际结果:有些俱乐部没有俱乐部固定装置,有些只有一个。
我试过这个 answer,但是出现错误,saveMany 不存在且关系为空。
您可以下载 SQL 结果数据库 here。
谁能告诉我我做错了什么?
试试这个
模态工厂
$factory->define(App\Club::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'league' => $faker->word,
'age_group' => $faker->word,
'colour' => $faker->hexcolor,
'county' => $faker->state,
'country' => $faker->country,
'emblem' => $faker->imageUrl(80, 80),
'banner' => $faker->imageUrl,
'matches' => $faker->randomDigit,
'wins' => $faker->randomDigit,
'losses' => $faker->randomDigit,
];
});
$factory->define(App\ClubFixture::class, function (Faker\Generator $faker) {
return [
'club_id' => function () {
return factory(App\Club::class,5)->create();
},
'opposition' => $faker->name,
'address' => $faker->address,
'datetime' => $faker->dateTimeBetween('now', '+30 weeks'),
'type' => $faker->randomElement(['home', 'away', 'none']),
];
});
您的 Models & Model Factories 看起来不错,但请将它们与此播种机一起使用:
use Illuminate\Database\Seeder;
class ClubSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Club::class, 100)->create()->each(function($c) {
/** @var \App\Club $c */
$c->fixtures()->saveMany(
factory(App\ClubFixture::class, 5)->make(['club_id' => NULL])
);
});
}
}
确保在 Club 模型的 fixtures()
关系方法上调用 saveMany()
方法。最后,还要为 5 个 ClubFixtures 的每次迭代覆盖 club_id
,以防止再次创建 Club。否则你最终会得到 600 个俱乐部(而不是 100 个俱乐部)和 500 个 ClubFixtures。
你应该这样做
'club_id' => function () {
return factory(App\Club::class,5)->create()->id;
},
对于 ClubFixture 工厂。
我是这样实现的:-
User.php(型号)
public function UserPortfolio(){
return $this->belongsTo(UserPortfolio::class,'id','user_id');
}
public function hasOnePortfolio(){
return $this->hasOne(UserPortfolio::class,'id','user_id');
}
DatabaseSeeder(种子)
$usersCount = (int)$this->command->ask('How many users do you need ? Default : ', 10);
factory(App\Promoter::class, $usersCount)->make()->each(function ($up) {
$up->hasOnePortfolio()->save(factory(App\UserPortfolio::class)->make());
});
$this->command->info('Users Created!');
$this->command->info('Users portfolio Updated!');
UserPortfolioFactory.php(工厂)
$factory->define(UserPortfolio::class, function (Faker $faker) {
return [
'user_id' => factory('App\User')->create()->id,
......
作为@baikho 答案的替代方法,您可以直接指定外键而不是使用 ->saveMany()
方法。我个人使用这个,因为我通常不使用 ->hasMany()
和其他关系方法。
use Illuminate\Database\Seeder;
class ClubSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Club::class, 100)->create()->each(function(App\Club $c) {
factory(App\ClubFixture::class, 5)->create(['club_id' => $c->id]);
});
}
}
请注意,在使用此语法时,您还想将 ->make()
方法更改为 ->create()
方法。
如果您的数据库架构不是第三规范化形式或者您有一些条件字段,这也会很有帮助。
例如,如果用户 (parent table) 是男性,则服装 (child table) 可以有某些选项不同于用户是女性。这些字段没有外键,但它们以用户为条件。
最后,您可以删除定义 $c 变量的 PHPDoc 注释,并将类名直接弹出到函数参数中。这样会更简洁、更清晰。
我在使用 Laravel 中的工厂为模型生成多个一对多关系时遇到问题。工厂似乎只为每个俱乐部生成一个 ClubFixture,而他们应该为每个俱乐部生成 5 个 ClubFixture。
型号
俱乐部
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Club extends Model
{
//Table associated with the model
protected $table = 'clubs';
protected $fillable = ['name', 'league', 'age_group', 'colour', 'county', 'country'];
public function fixtures(){
return $this->hasMany('App\ClubFixture', 'club_id', 'id');
}
}
俱乐部赛程
namespace App;
use Illuminate\Database\Eloquent\Model;
class ClubFixture extends Model
{
//Table associated with the model
protected $table = 'club_fixtures';
}
模态工厂
$factory->define(App\Club::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'league' => $faker->word,
'age_group' => $faker->word,
'colour' => $faker->hexcolor,
'county' => $faker->state,
'country' => $faker->country,
'emblem' => $faker->imageUrl(80, 80),
'banner' => $faker->imageUrl,
'matches' => $faker->randomDigit,
'wins' => $faker->randomDigit,
'losses' => $faker->randomDigit,
];
});
$factory->define(App\ClubFixture::class, function (Faker\Generator $faker) {
return [
'club_id' => function () {
return factory(App\Club::class)->create()->id;
},
'opposition' => $faker->name,
'address' => $faker->address,
'datetime' => $faker->dateTimeBetween('now', '+30 weeks'),
'type' => $faker->randomElement(['home', 'away', 'none']),
];
});
数据库播种机
factory(App\Club::class, 100)->create()->each(function ($u) {
factory(App\ClubFixture::class, 5)->create();
});
预期结果:每个俱乐部应该有 5 个与之关联的 ClubFixtures
实际结果:有些俱乐部没有俱乐部固定装置,有些只有一个。
我试过这个 answer,但是出现错误,saveMany 不存在且关系为空。
您可以下载 SQL 结果数据库 here。
谁能告诉我我做错了什么?
试试这个
模态工厂
$factory->define(App\Club::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'league' => $faker->word,
'age_group' => $faker->word,
'colour' => $faker->hexcolor,
'county' => $faker->state,
'country' => $faker->country,
'emblem' => $faker->imageUrl(80, 80),
'banner' => $faker->imageUrl,
'matches' => $faker->randomDigit,
'wins' => $faker->randomDigit,
'losses' => $faker->randomDigit,
];
});
$factory->define(App\ClubFixture::class, function (Faker\Generator $faker) {
return [
'club_id' => function () {
return factory(App\Club::class,5)->create();
},
'opposition' => $faker->name,
'address' => $faker->address,
'datetime' => $faker->dateTimeBetween('now', '+30 weeks'),
'type' => $faker->randomElement(['home', 'away', 'none']),
];
});
您的 Models & Model Factories 看起来不错,但请将它们与此播种机一起使用:
use Illuminate\Database\Seeder;
class ClubSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Club::class, 100)->create()->each(function($c) {
/** @var \App\Club $c */
$c->fixtures()->saveMany(
factory(App\ClubFixture::class, 5)->make(['club_id' => NULL])
);
});
}
}
确保在 Club 模型的 fixtures()
关系方法上调用 saveMany()
方法。最后,还要为 5 个 ClubFixtures 的每次迭代覆盖 club_id
,以防止再次创建 Club。否则你最终会得到 600 个俱乐部(而不是 100 个俱乐部)和 500 个 ClubFixtures。
你应该这样做
'club_id' => function () {
return factory(App\Club::class,5)->create()->id;
},
对于 ClubFixture 工厂。
我是这样实现的:-
User.php(型号)
public function UserPortfolio(){
return $this->belongsTo(UserPortfolio::class,'id','user_id');
}
public function hasOnePortfolio(){
return $this->hasOne(UserPortfolio::class,'id','user_id');
}
DatabaseSeeder(种子)
$usersCount = (int)$this->command->ask('How many users do you need ? Default : ', 10);
factory(App\Promoter::class, $usersCount)->make()->each(function ($up) {
$up->hasOnePortfolio()->save(factory(App\UserPortfolio::class)->make());
});
$this->command->info('Users Created!');
$this->command->info('Users portfolio Updated!');
UserPortfolioFactory.php(工厂)
$factory->define(UserPortfolio::class, function (Faker $faker) {
return [
'user_id' => factory('App\User')->create()->id,
......
作为@baikho 答案的替代方法,您可以直接指定外键而不是使用 ->saveMany()
方法。我个人使用这个,因为我通常不使用 ->hasMany()
和其他关系方法。
use Illuminate\Database\Seeder;
class ClubSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
factory(App\Club::class, 100)->create()->each(function(App\Club $c) {
factory(App\ClubFixture::class, 5)->create(['club_id' => $c->id]);
});
}
}
请注意,在使用此语法时,您还想将 ->make()
方法更改为 ->create()
方法。
如果您的数据库架构不是第三规范化形式或者您有一些条件字段,这也会很有帮助。
例如,如果用户 (parent table) 是男性,则服装 (child table) 可以有某些选项不同于用户是女性。这些字段没有外键,但它们以用户为条件。
最后,您可以删除定义 $c 变量的 PHPDoc 注释,并将类名直接弹出到函数参数中。这样会更简洁、更清晰。