Symfony Doctrine新建Expense关联已有PaymentMethod不新增数据方法
问题描述
需要创建与PaymentMethod实体为ManyToOne关联关系的expense对象,要求新建expense时直接引用数据库中已存在的PaymentMethod记录,不生成新的PaymentMethod数据。
初始相关代码如下:
控制器初始代码
$expense->setPaymentMethod( // 下方写法会在数据库新增不需要的PaymentMethod对象 //$paymentMethod->setPaymentMethod('Card') //此处应当如何编写? ); $expense->setBoughtDate($time); $this->entityManager->persist($expense); $this->entityManager->flush();
Expense实体初始定义
class Expense { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] #[Groups(["expense:list", "expense:item"])] private int $id; #[ORM\ManyToOne(targetEntity: PaymentMethod::class, cascade: ['persist'])] #[ORM\JoinColumn(nullable: true)] private ?PaymentMethod $paymentMethod = null; // 下方为Getter和Setter方法
PaymentMethod实体定义
class PaymentMethod { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private int $id; #[ORM\Column(type: 'string', length: 64)] private string $paymentMethod;
问题原因
之前写法会自动新增PaymentMethod记录有两个核心原因:
- 赋值时传入的是手动实例化的、未被Doctrine EntityManager托管的新PaymentMethod对象
- Expense实体的ManyToOne关联配置了
cascade: ['persist'],Doctrine会在持久化Expense时,自动级联持久化关联的所有非托管状态的新对象,直接生成插入SQL。
实现方案
核心逻辑:给setPaymentMethod()传入从数据库查询得到的、已被EntityManager托管的PaymentMethod实体对象即可,Doctrine会自动识别这是已存在的记录,只会建立外键关联,不会生成新的PaymentMethod插入语句。
标准写法
通过注入PaymentMethodRepository,查询出已存在的记录后再赋值,支持按主键、字段条件查询:
// 方式1:按主键ID查询 $paymentMethod = $this->paymentMethodRepository->find(5); // 方式2:按支付方式名称查询 // $paymentMethod = $this->paymentMethodRepository->findOneBy(['paymentMethod' => 'Card']); $expense->setPaymentMethod($paymentMethod); $expense->setBoughtDate($time); $this->entityManager->persist($expense); $this->entityManager->flush();
配置优化建议
如果业务上PaymentMethod是固定基础数据,永远不需要在新增Expense时同步创建,建议移除关联配置中不必要的cascade: ['persist'],从根源避免误传新对象时生成脏数据:
// 调整后的Expense关联配置 #[ORM\ManyToOne(targetEntity: PaymentMethod::class)] #[ORM\JoinColumn(nullable: true)] private ?PaymentMethod $paymentMethod = null;
补充:你之前通过
$this->paymentMethodRepository->findOneBy(['id'=> 5])查询后赋值的写法已经完全符合要求,可以正常实现需求。
内容的提问来源于stack exchange,提问作者MatZyn
相关产品推荐
相关产品推荐

