Symfony2:通过一对一关系连接的持久实体。 FK字段永远不会设置

时间:2014-04-29 10:52:36

标签: symfony doctrine-orm

我花了好几个小时才解决这个问题而无法使用它(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

1 个答案:

答案 0 :(得分:2)

class Customer

    public function setInvoiceAddress($invoiceAddress)
    {
        $this->invoiceAddress = $invoiceAddress;
        $invoiceAddress->setCustomer($this); // *** ADD THIS ***
    }

这是一个非常常见的问题。只是很难搜索。