OneToMany关系未与新实体一起持续存在



当我试图使用符号形式持久化实体集合时,我遇到了一些问题。我遵循了官方文档,但由于以下错误,我无法使其工作:

Entity of type ProductItem has identity through a
foreign entity Product, however this entity has no identity itself. You have to call    
EntityManager#persist() on the related  entity and make sure that an identifier was 
generated before trying to persist ProductItem. In case of Post Insert ID 
Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you 
have to call EntityManager#flush() between both persist operations.

我必须与OneToMany关系链接的实体:

产品

/**
* @ORMColumn(name="id", type="integer", nullable=false)
* @ORMId
* @ORMGeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORMOneToMany(targetEntity="ProductItem", mappedBy="product",cascade={"persist"})
*/
protected $items;

和ProductItem

/**
* @ORMId()
* @ORMManyToOne(targetEntity="Product", inversedBy="items")
*/
protected $product;
/**
* @ORMId()
* @ORMManyToOne(targetEntity="Item")
*/
protected $item;

这就是它添加到表单中的方式:

->add('items','collection',array(
'label' => false,
'type' => new ProductItemType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false))

这是控制器的动作:

public function newAction()
{
$product= new Product();
$form = $this->createForm(new ProductType(), $product);
if($request->isMethod("POST"))
{
$form->handleRequest($request);
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
}
}
}

我在控制器中肯定做错了什么,因为正如错误消息所说,在添加$productItems之前,我必须保持$product,但我该怎么做呢

我只有在尝试持久化新实体时才会出现此错误,如果该实体以前已经持久化,我可以根据需要添加任意项目成功

上周我遇到了完全相同的问题,这是我在阅读和测试后找到的解决方案。

问题是,您的Product实体具有级联持久化(这通常很好),它首先尝试持久化ProductItem,但ProductItem实体无法持久化,因为它们需要首先持久化Product及其ID(组合键(Product,item))。

有两种解决方案:

1st我没有使用它,但您可以简单地丢弃一个复合密钥,并使用Product的带有外键的标准id

第二-更好这可能看起来像黑客,但相信我,这是你现在能做的最好的事情。它不需要对DB结构进行任何更改,并且可以毫无问题地处理表单集合。

我的代码中的代码片段,文章部分具有复合键(article_id,random_hash)。临时设置对空数组的一对多引用,持久化它,添加原始数据并再次持久化(和刷新)。

if ($form->isValid())
{
$manager = $this->getDoctrine()->getManager();
$articleSections = $article->getArticleSections();
$article->setArticleSections(array());  // this won't trigger cascade persist
$manager->persist($article);
$manager->flush();
$article->setArticleSections($articleSections);
$manager->persist($article);
$manager->flush();

您没有完全遵循文档。以下是您可以测试单个item的方法,但如果您想动态添加和删除项目(看起来像这样),您还需要实现链接到的文档中包含的所有javascript。

$product= new Product();
$productItem = new ProductItem();
// $items must be an arraycollection
$product->getItems()->add($productItem);
$form = $this->createForm(new ProductType(), $product);
if($request->isMethod("POST"))
{
$form->handleRequest($request);
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($productItem);
$em->persist($product);
$em->flush();
}
}

因此,这应该适用于单个静态item,但正如我所说,动态的东西需要更多的工作。

注释错误。。。级联持久性在关系的错误一侧

/**
* @ORMOneToMany(targetEntity="ProductItem", mappedBy="product")
*/
protected $items;

/**
* @ORMId()
* @ORMManyToOne(targetEntity="Product", inversedBy="items", cascade={"persist"})
*/
protected $product;

实现这一点的另一种方法(例如,注释不可能)是通过引用设置表单

IMO,您的问题与您的控制器无关,而是与您的实体有关。您似乎希望在Product和Item之间创建一个ManyToMany,而不是创建一个ProductItem类,该类应充当表示关系的中间对象。此外,这个中间对象没有id生成策略。这就是为什么Doctrine解释说,你必须首先持久化/刷新所有新项目,然后持久化/清除你的产品,才能获得中间对象的id。

在处理CollectionType字段所附加的表单时也遇到了这个问题。另一种可以解决这个问题的方法,也在条令官方文件中提到,如下所示:

public function newAction()
{
$product= new Product();
$form = $this->createForm(new ProductType(), $product);
if($request->isMethod("POST"))
{
$form->handleRequest($request);
if($form->isValid())
{
foreach ($product->getItems() as $item)
{
$item->setProduct($product);
}
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
}
}
}

简单地说,您应该手动为链接的项目提供产品链接——这在以下文章的"建立关联"部分进行了描述:http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#working-与关联

相关内容

  • 没有找到相关文章

最新更新