Symfony实体工厂搭配DiscriminatorColumn无法运行问题求助
问题分析
你遇到的错误根源是:Doctrine的鉴别器列(DiscriminatorColumn)是ORM内部用于区分继承子类的字段,Contact实体本身并没有定义type属性,也不需要手动设置。你在工厂的getDefaults里直接指定'type' => Person::class,Foundry会尝试给Contact实体设置不存在的type属性,自然会触发"无法访问属性"的错误。
解决方法
以下是两种符合Doctrine设计规范的可行方案,优先推荐第一种:
方案一:为每个子类创建独立工厂
针对Person、Family、Company这三个子类分别创建工厂,直接实例化子类而非父类Contact,让Doctrine自动处理鉴别器列。
示例PersonFactory代码:
namespace App\Factory; use App\Entity\ContactType\Person; use Zenstruck\Foundry\ModelFactory; class PersonFactory extends ModelFactory { protected function getDefaults(): array { return [ 'createdAt' => self::faker()->dateTime(), 'isArchived' => 0, // 这里可以添加Person专属属性 ]; } protected static function getClass(): string { return Person::class; } }
同理创建FamilyFactory和CompanyFactory后,修改Fixtures代码:
public function load(ObjectManager $manager): void { $user = UserFactory::createOne(); // 按需创建不同类型的联系人 PersonFactory::createMany(3, ['createdBy' => $user]); FamilyFactory::createMany(1, ['createdBy' => $user]); CompanyFactory::createMany(1, ['createdBy' => $user]); $manager->flush(); }
方案二:修改ContactFactory动态生成子类实例
如果不想创建多个工厂,可以在ContactFactory中通过状态方法或随机逻辑,直接实例化子类,避免手动设置type属性。
修改后的ContactFactory代码:
namespace App\Factory; use App\Entity\Contact; use App\Entity\ContactType\Company; use App\Entity\ContactType\Family; use App\Entity\ContactType\Person; use Zenstruck\Foundry\ModelFactory; class ContactFactory extends ModelFactory { protected function getDefaults(): array { return [ 'createdAt' => self::faker()->dateTime(), 'isArchived' => 0, ]; } // 状态方法:指定生成Person类型 public function asPerson(): self { return $this->instantiateWith(fn() => new Person()); } // 状态方法:指定生成Family类型 public function asFamily(): self { return $this->instantiateWith(fn() => new Family()); } // 状态方法:指定生成Company类型 public function asCompany(): self { return $this->instantiateWith(fn() => new Company()); } // 可选:默认随机生成子类 protected static function instantiate(array $attributes): object { $types = [Person::class, Family::class, Company::class]; $class = self::faker()->randomElement($types); return new $class(); } protected static function getClass(): string { return Contact::class; } }
Fixtures中的使用方式:
public function load(ObjectManager $manager): void { $user = UserFactory::createOne(); // 指定类型创建 ContactFactory::new()->asPerson()->many(3)->create(['createdBy' => $user]); // 随机类型创建 ContactFactory::createMany(2, ['createdBy' => $user]); $manager->flush(); }
不推荐的方案
不要尝试给Contact实体添加type属性或setType方法——鉴别器列是Doctrine内部管理的字段,手动干预可能导致数据一致性问题。
内容的提问来源于stack exchange,提问作者Morpheus_ro
相关产品推荐
相关产品推荐

