Doctrine2:多次调用flush


Doctrine2: calling flush multiple times

我有一个关于原则Symfony 2.3上的实体的问题。

根据v2.3 "文档手册"章节"数据库和理论"";保存相关实体,本例同时在productcategory表中创建新行,并将 product.category_id值与新类别项的id相关联。

问题是控制器动作在调用时创建了一个新的Product和一个新的Category !

为了创建一个新的产品并将其category_id与现有的类别 id关联,这是路由。yml 路线:
acme_store_create_product_by_category:
path:     /create/newproduct/{name}/{categoryId}
defaults: { _controller: AcmeStoreBundle:Default:createProduct }

我做了一个测试通过URL传递参数:
/web/商店/创建/newproduct/Kayak/12

我做了这样的事情,似乎工作得很好:

public function createProductAction($name, $categoryId)
{
    $em = $this->getDoctrine()->getManager();
    if ( $em->getRepository("AcmeStoreBundle:Category")->findOneById($categoryId) ) {
        $product = new Product();
        $product->setName($name);
        $product->setPrice(220);
        $product->setDescription("This is just a test");
        $em->persist($product);
        $em->flush();
        $newproduct = $em->getRepository("AcmeStoreBundle:Product")->find($product->getId());
        /** Create new product and populate $newproduct with its data */

        $repository = $em->getRepository("AcmeStoreBundle:Category")->find($categoryId);
        $newproduct->setCategory($repository);
        $em->persist($newproduct);
        $em->flush();
        /** Update the id_category field of the new product with parameter $categoryId */
        //exit('Doctrine'Common'Util'Debug::dump($product));
        return new Response('Create product ' . $name . ' with category id ' . $categoryId);
    } else {
        return new Response('It doesn''t exists any category with id ' . $categoryId);
    }
}
在这种情况下,我的疑问是:在相同的操作中调用flush()方法两次是一个好做法吗?在本例中,我想创建一个新的产品,从列表框中选择相关的类别

提前感谢!

我认为这主要取决于您的应用程序领域。如果你运行flush两次,这意味着你运行了两个事务。在第一个中,您持久化一个产品,在第二个中持久化一个类别。因此,如果第一个事务失败(假设您在产品名称上有一个唯一的键,并且您试图持久化具有相同名称的产品,因此您得到一个重复的键异常),那么问自己是否可以继续持久化一个类别。我不认为我们可以在这里轻松地回答这个问题,因为我认为这取决于你的应用程序逻辑,端点应该做什么,如果你最终拥有一个产品而不是一个类别会发生什么,反之亦然。

你还应该考虑,如果你在第一个事务中得到一个异常,你的代码将无法处理这个错误,因此第二个事务将失败。当出现类似重复键的异常时,所有实体都被分离,实体管理器不再知道如何管理事物。所以你必须重置它,否则你会得到一个EntityManager is closed问题。

try {
    // first transaction
    $entityManager->persist($entityOne);
    $entityManager->flush();
} catch ('Exception $e) {
    /* ... handle the exception */ 
    $entityManager->resetManager();
}
// now we can safely run a second transaction here

我希望这能回答你的问题:-)

我建议使用编辑后的代码片段

    public function createProductAction($name, $categoryId)
    {
        $em = $this->getDoctrine()->getManager();
    
        if ( $em->getRepository("AcmeStoreBundle:Category")->findOneById($categoryId) ) {
    
            $repository = $em->getRepository("AcmeStoreBundle:Category")->find($categoryId);
    
            $product = new Product();
            $product->setName($name);
            $product->setPrice(220);
            $product->setDescription("This is just a test");
            $product->setCategory($repository);
    
            $em->persist($product);
            $em->flush();
    
            return new Response('Create product ' . $name . ' with category id ' . $categoryId);
    
        } else {
    
            return new Response('It doesn''t exists any category with id ' . $categoryId);
        }
    }