Factory 默认只造对象不入库,想写进数据库必须用 create() 而非 make();make() 仅返回未保存的 Eloquent 实例,不触发 save()、事务或事件,适用于单元测试中验证 accessor/mutator 等逻辑。

Factory 默认只造对象不入库,想写进数据库必须用 create(),不是 make() —— 这是 90% 的人第一次跑测试失败的根源。
为什么 User::factory()->make() 数据没出现在数据库里?
因为 make() 只调用模型构造器,返回一个未保存的 Eloquent 实例。它连 save() 都不触发,更别说事务或事件了。
- 适合场景:单元测试中验证
accessor、mutator、自定义方法逻辑,完全绕开 DB - 不适合场景:需要查关联、测软删除、依赖真实 ID 或外键约束的集成测试
- 常见错误现象:
Post::factory()->for($user)->make()后查$user->posts返回空集合——$user本身可能也是make()出来的临时对象,没 ID,也没存库
create() 报错 “Integrity constraint violation: 1452” 怎么办?
典型是外键字段(如 user_id)指向了一个未持久化的模型。Laravel 的 for() 方法要求传入的是已 create() 过的对象,不能是 make() 出来的。
- 正确写法:
$user = User::factory()->create(); Post::factory()->for($user)->create(); - 批量安全写法:
Post::factory()->for(User::factory())->create();—— 工厂内部自动先create()父模型再建子模型 - 别在
definition()里手动写'user_id' => User::factory()->create()->id,这会引发循环创建和 N+1 查询 - 如果父模型工厂没定义
$model属性或路径错位,for(User::factory())会静默失败或抛Target class [...] does not exist
怎么给非 Eloquent 类或无表模型写 Factory?
Laravel 官方 Factory 是为 Eloquent 模型设计的,强行绑定 $model 到一个没有 $table 的类上,create() 会直接报错。这时候别硬套,换思路。
- 优先用纯数组工厂:在
database/factories/下新建UserSettingFactory.php,直接return [...]闭包,不用继承Factory - 需要实例化时,手动构造:
$data = UserSettingFactory::new()->make(); $setting = new UserSetting($data); - 绝对不要在
definition()里调用DB::insert()或其他业务逻辑 —— 工厂只负责数据形状,不负责副作用 - 若必须复用 Faker 行为,直接用
fake()->boolean(),别 newFaker\Generator,否则unique()失效
Seeder 里大批量生成数据慢或爆内存?
默认 User::factory()->count(1000)->create() 是逐条插入 + 触发所有模型事件,对性能很不友好。
- 关事件:
User::withoutEvents(fn () => User::factory()->count(1000)->create()); - 避免观察者干扰:确保
App\Providers\EventServiceProvider中没全局注册监听器 - 主键重置问题:批量插入后 ID 不连续,但测试中一般不影响;真要连续,得手动
DB::statement('ALTER TABLE users AUTO_INCREMENT = 1') - 别在工厂
afterCreating()里做耗时操作(如发邮件、调 API),那会把 Seeder 变成串行阻塞任务
最易被忽略的一点:工厂类文件名、类名、命名空间、$model 值四者必须严丝合缝。哪怕 database/factories/UserFactory.php 里写错一个 \App\Models\User::class 的命名空间前缀,User::factory() 就会静默回退到空工厂,然后所有字段都是 null —— 错误不会立刻报,而是等你查数据时才发现字段全空。











