我花了好几个小时才解决这个问题而无法使用它(Symfony2和Doctrine2新增了)。
场景:我基本上有一对一关系的2个实体:客户< - >地址。仅供记录:客户和地址正在使用Doctrine的单表继承功能。因此,客户始终是PrivateCustomer或BusinessCustomer。 “地址”是InvoiceAddress或DeliveryAddress等....也许问题与STI有关。
问题:我在Customer表单中使用InvoiceAddress实体的嵌入表单,以便在创建新客户时创建它。 TRednering工作正常,但是当我持久/刷新客户时,会创建一个新客户并创建一个新的发票地址,但invoiceAddress customer_id为NULL,因此两者永远不会被绑定(当然FK约束失败)。我的理解是Doctrine会在事务中包装所有内容并自动分配customer_id。我错了吗?如果我在客户之前手动持有invoiceAddress,它就有效,但我觉得这不是必需的。
代码(相关部分):
InvoiceAddress:
namespace Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* InvoiceAddress
*
* @ORM\Entity
*/
class InvoiceAddress extends Address
{
/**
* @var Entity\Customer
*
* @ORM\OneToOne(targetEntity="Entity\Customer", inversedBy="invoiceAddress")
* @ORM\JoinColumn(name="customer_id", referencedColumnName="id", nullable=FALSE)
*/
private $customer;
/**
* @param Entity\Customer $customer
*/
public function setCustomer($customer)
{
$this->customer = $customer;
}
/**
* @return Entity\Customer
*/
public function getCustomer()
{
return $this->customer;
}
}
客户:
namespace Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
use Entity\User;
/**
* Customer
*
* @ORM\Entity(repositoryClass="Repository\CustomerRepository")
* @ORM\Table(name="customer")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"private" = "Entity\PrivateCustomer", "business" = "Entity\BusinessCustomer"})
*/
class Customer
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
.... OTHER FIELDS ......
/**
* @var \Entity\InvoiceAddress
*
* @Assert\Valid
*
* @ORM\OneToOne(targetEntity="Entity\InvoiceAddress", mappedBy="customer", cascade={"persist", "remove"}, orphanRemoval=true, fetch="EAGER")
*/
private $invoiceAddress;
/**
* @var \Entity\DeliveryAddress
*
* @Assert\Valid
*
* @ORM\OneToOne(targetEntity="DeliveryAddress", mappedBy="customer", cascade={"persist", "remove"}, orphanRemoval=true, fetch="LAZY")
*/
private $deliveryAddress;
/**
* @var \Entity\MarketingAddress
*
* @Assert\Valid
*
* @ORM\OneToOne(targetEntity="Entity\MarketingAddress", mappedBy="customer", cascade={"persist", "remove"}, orphanRemoval=true, fetch="LAZY")
*/
private $marketingAddress;
/**
* @var ArrayCollection Entity\Contact
*
* @Assert\Valid
*
* @ORM\OneToMany(targetEntity="Entity\Contact", mappedBy="customer", cascade={"persist", "remove"}, orphanRemoval=true, fetch="LAZY")
*/
private $contacts;
public function __construct()
{
$this->contacts = new ArrayCollection();
}
/**
* @return ArrayCollection
*/
public function getContacts()
{
return $this->contacts;
}
/**
* @param Contact $contact
*/
public function addContact(Contact $contact)
{
if (!$this->contacts->contains($contact)) {
$this->contacts->add($contact);
$contact->setCustomer($this);
}
}
/**
* @param Contact $contact
*/
public function removeContact(Contact $contact)
{
if ($this->contacts->contains($contact)) {
$this->contacts->removeElement($contact);
$contact->unsetCustomer();
}
}
/**
* @param Entity\MarketingAddress $marketingAddress
*/
public function setMarketingAddress($marketingAddress)
{
$this->marketingAddress = $marketingAddress;
}
/**
* @return Entity\MarketingAddress
*/
public function getMarketingAddress()
{
return $this->marketingAddress;
}
/**
* @param DeliveryAddress $deliveryAddress
*/
public function setDeliveryAddress($deliveryAddress)
{
$this->deliveryAddress = $deliveryAddress;
}
/**
* @return Entity\DeliveryAddress
*/
public function getDeliveryAddress()
{
return $this->deliveryAddress;
}
/**
* @param Entity\InvoiceAddress $invoiceAddress
*/
public function setInvoiceAddress($invoiceAddress)
{
$this->invoiceAddress = $invoiceAddress;
}
/**
* @return Entity\InvoiceAddress
*/
public function getInvoiceAddress()
{
return $this->invoiceAddress;
}
}
CustomerController中的操作
/**
* Creates a new PrivateCustomer entity.
*
* @Route("/private", name="customer_create_private")
* @Method("POST")
* @Template("Customer:private_new.html.twig")
*/
public function createPrivateAction(Request $request)
{
$customer = new PrivateCustomer();
$form = $this->createCreateForm($customer);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($customer);
$em->flush();
return $this->redirect($this->generateUrl('customer_private_edit', array('id' => $customer->getId())));
}
return array(
'entity' => $customer,
'form' => $form->createView(),
);
}
在CustomerType中,我定义了invoiceAddress字段,如此
$builder->add('invoiceAddress', new InvoiceAddressType(), array(
'label' => 'Rechnungsadresse',
'label_render' => false,
'widget_form_group_attr' => array(
'class' => 'form-inline'
)
));
问题:我必须手动执行
$em->persist($customer->getInvoiceAddress())
$em->persist($customer)
只是为了设置FK。我认为Doctrine的魔法应该照顾它(因为CASCADE =“persist”选项)。 THX
答案 0 :(得分:2)
class Customer
public function setInvoiceAddress($invoiceAddress)
{
$this->invoiceAddress = $invoiceAddress;
$invoiceAddress->setCustomer($this); // *** ADD THIS ***
}
这是一个非常常见的问题。只是很难搜索。