You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:33:35