Doctrine和ZF2:存储ManyToOne关系而不进行级联

时间:2014-02-28 00:20:44

标签: doctrine-orm zend-framework2

我正在努力正确设置实体。 情况如下:

“国家/地区”有一个或多个“客户”

我是一个包含所有国家/地区的国家/地区表,我想为每个客户保存对国家/地区的引用。很简单,经常需要。

但我无法正确配置实体。如果我没有在“Customer”类中定义级联方法,我会得到一个例外。如果我添加级联方法,那么国家/地区对象也会作为新记录添加到国家/地区表中,但我只想在Customer表中引用此对象。

客户类

/**
 * @ORM\Entity
 * @ORM\Table(name="PS_Customer")
 */
class Customer {
/**
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 * @ORM\Column(type="integer")
 */
protected $id;

/**
 * @ORM\ManyToOne(targetEntity="Country",inversedBy="id")
 * @ORM\JoinColumn(name="country_id", referencedColumnName="id")
 */
protected $country;
}

国家/地区类

/**
 * @ORM\Entity
 * @ORM\Table(name="PS_Country")
 */
class Country {
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     * @ORM\OneToMany(targetEntity="Customer", mappedBy="country")
     */
    protected $id;

    /** @ORM\Column(type="string") */
    protected $name;

    /** @ORM\Column(type="string") */
    protected $iso2;

}

如果我想使用此定义存储Customer对象,则会收到以下错误:

A new entity was found through the relationship 'Photoshop\Entity\Customer#country' that was not configured to cascade persist operations for entity: Photoshop\Entity\Country@000000004c6f8efb00000000b695d273. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist  this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Photoshop\Entity\Country#__toString()' to get a clue.

ActionController(已解压缩):

$forms = $this->getServiceLocator()->get('FormElementManager');
$form = $forms->get('Photoshop\Form\CheckoutForm');
$customer = new Customer;
$form->bind($customer);

$order = new Order;
$order->setCustomer($customer);

// Order object is put into a session during checkout process here...

/**
* Commit Order to database
*/
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$em->persist($sessionCheckout->order); // Fetch the order object from session
$em->flush();

结帐表格

class CheckoutForm extends Form implements ObjectManagerAwareInterface {

    protected $objectManager;

    public function __construct() {
        parent::__construct('checkout');

    }

    public function init() {

        $this->setAttribute('action', 'checkout');
        $this->setAttribute('method', 'post');
        $this->setHydrator(new DoctrineHydrator($this->getObjectManager()));
        $this->setInputFilter(new \Photoshop\Form\CheckoutFilter());

        $this->add(array(
            'name' => 'country',
            'type' => 'DoctrineModule\Form\Element\ObjectSelect',
            'options' => array(
                'label' => 'Country:',
                'empty_option'    => 'Please choose...',
                'object_manager' => $this->getObjectManager(),
                'target_class' => 'Photoshop\Entity\Country',
                'property' => 'name',
            ),
        ));

        $this->add(array(
            'type' => 'Zend\Form\Element\Select',
            'name' => 'gender',
            'options' => array(
                'label' => 'Title*:',
                'empty_option' => 'Please choose...',
                'value_options' => array(
                    'f' => 'Mrs.',
                    'm' => 'Mr.'
                ),
            )
        ));

        $this->add(array(
            'name' => 'firstName',
            'attributes' => array(
                'type' => 'text',
                'id' => 'firstName'
            ),
            'options' => array(
                'label' => 'First name*:'
            ),
        ));

        $this->add(array(
            'name' => 'lastName',
            'attributes' => array(
                'type' => 'text',
                'id' => 'lastName'
            ),
            'options' => array(
                'label' => 'Last name*:'
            ),
        ));


        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'type' => 'submit',
                'value' => 'Pay with PayPal or Credit Card now',
                'class' => 'btn btn-primary btn-lg btn-block'
            )
        ));

    }

    public function setObjectManager(ObjectManager $objectManager) {
        $this->objectManager = $objectManager;
    }

    /**
     * Get the object manager
     *
     * @return ObjectManager
     */
    public function getObjectManager() {
        return $this->objectManager;
    }

}

我很确定解决起来很简单。但我现在看不到解决方案:)

也许有人可以给我一个提示?!?会很感激...

谢谢, 迈克尔

1 个答案:

答案 0 :(得分:2)

//在此结账过程中将订单对象放入会话中......这是重要的部分

因此,如果我理解,您可以在一个请求中创建订单和客户,然后通过会话将其转移到其他请求并将其保留在那里。真正发生的是你有像order-> customer-> country这样的对象图,前两个是新实体,所以序列化反序列化对它们没有任何问题,但country是已经存在于DB中的被管实体。通过将其序列化为会话,它与实体管理器分离,并且在反序列化之后,它被呈现给新的实体管理器实例,该实例管理器实例不知道它曾经被管理过,因此决定持久化是新的实体管理器实例。

通常您需要将未序列化的实体合并到当前的实体管理器

$managedOrder = $em->merge($sessionCheckout->order);

并使用$ managedOrder。为此,您可能需要在Customer :: country和Order :: customer上设置cascade = {“merge”}。

Doctrine有关于此主题的Entities in session文档页面。