如何将一个对象与多个相关对象持久化


How to persist one object with many related objects

我有实体BasketBasketItem:

/**
 * Acme'BasketBundle'Entity'Basket
 *
 * @ORM'Entity(repositoryClass="Acme'BasketBundle'Repository'BasketRepository")
 * @ORM'Table(name="orders")
 * @ORM'HasLifecycleCallbacks()
 */
class Basket
{
  /**
   * @var integer $id
   *
   * @ORM'Column(name="id", type="integer")
   * @ORM'Id
   * @ORM'GeneratedValue(strategy="AUTO")
   */
  private $id;
  // ...
  /**
    * @ORM'OneToMany(targetEntity="BasketItem", mappedBy="order_id",cascade={"all"})
    */
  protected $items;
  // ...
  public function __construct() {
    $this->items = new ArrayCollection();
  }
  /**
   * Add item
   *
   * @param BasketItem $item
   */
  public function addItem(BasketItem $item)
  {
    $key = $this->find($item->getProduct()->getId());
    if ($key === false) {
        $this->items->add($item);
    } else {
        $this->items->get($key)->raiseQuantity($item->getQuantity());
    }
  }
  /**
   * Find an item (if present)
   *
   * @param integer $id
   * @return integer
   */
  public function find($id)
  {
    foreach ($this->items as $key => $item) {
        if ($item->getProduct()->getId() == $id)
            return $key;
    }
    return false;
  }
}


/**
 * Acme'BasketBundle'Entity'BasketItem
 *
 * @ORM'Entity
 * @ORM'Table(name="order_items")
 */
class BasketItem
{
  /**
   * @var integer $id
   *
   * @ORM'Column(name="id", type="integer")
   * @ORM'Id
   * @ORM'GeneratedValue(strategy="AUTO")
   */
  private $id;
  // ...
  /**
   * @ORM'ManyToOne(targetEntity="Basket", inversedBy="items")
   * @ORM'JoinColumn(name="order_id", referencedColumnName="id")
   */
  private $basket;
  // ...
}

现在,当我创建一个篮子并将其装满项目时,我很难将其持久化到数据库中。

以下操作没有按预期进行。

$basket = new Basket();
$basket->addItem(new BasketItem($product1, 1));
$basket->addItem(new BasketItem($product2, 2));
$em->persist($basket);
$em->flush();

然后我试着更仔细地遵循手册:

$basket = new Basket();
$basket->addItem(new BasketItem($product1, 1));
$basket->addItem(new BasketItem($product2, 2));
$em->persist($basket);
foreach ($basket->getItems() as $item) {
    $em->persist($item);
}
$em->flush();

这也没有像预期的那样奏效。

在这两种情况下,所有数据都会保存到数据库,但购物篮项目与购物篮无关,即BasketItem实体的order_idNULL

有人能解释一下我做错了什么吗?请注意,我是新的学说。谢谢




编辑

我已经很困惑了。这是我的简化测试:

<?php
namespace Amsel'BasketBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use Doctrine'Common'Collections'ArrayCollection;
/**
 * Amsel'BasketBundle'Entity'Basket
 *
 * @ORM'Entity(repositoryClass="Amsel'BasketBundle'Repository'BasketRepository")
 * @ORM'Table(name="orders")
 */
class Basket
{
    /**
     * @var integer $id
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var ArrayCollection $items
     *
     * @ORM'OneToMany(targetEntity="BasketItem", mappedBy="basket", cascade={"all"})
     */
    protected $items;
    public function __construct() {
        $this->items = new ArrayCollection();
    }
    /**
     * Add item
     *
     * @param BasketItem $item
     */
    public function addItem(BasketItem $item)
    {
        $this->items->add($item);
    }
    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Get items
     *
     * @return Doctrine'Common'Collections'Collection 
     */
    public function getItems()
    {
        return $this->items;
    }
}


<?php
namespace Amsel'BasketBundle'Entity;
use Doctrine'ORM'Mapping as ORM;

/**
 * Amsel'BasketBundle'Entity'BasketItem
 *
 * @ORM'Entity(repositoryClass="Amsel'BasketBundle'Repository'BasketItemRepository")
 * @ORM'Table(name="order_items")
 */
class BasketItem
{
    /**
     * @var integer $id
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var Basket $basket
     *
     * @ORM'ManyToOne(targetEntity="Basket", inversedBy="items")
     * @ORM'JoinColumn(name="order_id", referencedColumnName="id")
     */
    protected $basket;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Set basket
     *
     * @param Amsel'BasketBundle'Entity'Basket $basket
     */
    public function setBasket('Amsel'BasketBundle'Entity'Basket $basket)
    {
        $this->basket = $basket;
    }
    /**
     * Get basket
     *
     * @return Amsel'BasketBundle'Entity'Basket 
     */
    public function getBasket()
    {
        return $this->basket;
    }
}


public function testAction(Request $request) {
    $em = $this->getDoctrine()->getEntityManager();
    $basket = new Basket();
    $basket->addItem(new BasketItem());
    $basket->addItem(new BasketItem());
    $em->persist($basket);
    try {
        $em->flush();
    } catch(Exception $e) {
        die('ERROR: '.$e->getMessage());
    }        
    die ('end');
}

但仍然-订单项(BasketItem)已存储,但链接到订单(Basket)。

Basket实体中的注释映射错误:"mappedBy"属性必须引用实体字段,而不是数据库列。

/**  
 * @ORM'OneToMany(targetEntity="BasketItem", mappedBy="basket",cascade={"all"})  
 */  
 protected $items;

如果我正确理解系统,我还必须手动将父Basket实体分配给每个BasketItem实体,因为这是一个双向关系。

public function testAction(Request $request) {
    $em = $this->getDoctrine()->getEntityManager();
    $basket = new Basket();
    $bi1 = new BasketItem();
    $bi1->setBasket($basket);
    $bi2 = new BasketItem();
    $bi2->setBasket($basket);
    $basket->addItem($bi1);
    $basket->addItem($bi2);
    $em->persist($basket);
    try {
        $em->flush();
    } catch(Exception $e) {
        die('ERROR: '.$e->getMessage());
    }        
    die ('end');
}

这样做很好,但如果我走错了路,请纠正我。

感谢所有花时间研究我问题的人!

我是Symfony and Doctrine的新手,但这很奇怪。我认为它应该双向工作,但似乎你必须在BasketItem 上设置Basket

$bi->setBasket($basket);

如果你想让它双向工作,例如:

$basket->addItem($bi);

你必须修改你的addItem方法和removeItem方法

/**
 * Add item
 *
 * @param BasketItem $item
 */
public function addItem(BasketItem $item)
{
    $item->setBasket($this);
    $this->items->add($item);
}
/**
 * Remove item
 *
 * @param BasketItem $item
 */
public function removeItem(BasketItem $item)
{
    $item->setBasket(null);
    $this->items->removeElement($item);
}

[EDIT]如下所示:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#owning-和多人对多人关联