symfony 原则2-一次插入多个

kq4fsx7k  于 2022-11-16  发布在  其他
关注(0)|答案(5)|浏览(178)

我是Doctrine的新手,对我来说还有一些模糊的地方。在这个例子中,我使用循环和实体管理器在数据库中插入新记录。它工作正常,但我注意到Doctrine按实体进行一次插入查询,这可能会变得相当大。
使用Doctrine2和Symfony 2.3,我想知道我们如何设置它,使它只生成一个插入查询,其中包含所有值(当然,我们只讨论1个实体)。
我的意思是改变这一点:

INSERT INTO dummy_table VALUES (x1, y1)    
INSERT INTO dummy_table VALUES (x2, y2)

进入

INSERT INTO dummy_table VALUES (x1, y1), (x2, y2)

下面是我的代码:

$em = $this->container->get('doctrine')->getManager();

foreach($items as $item){
    $newItem = new Product($item['datas']);
    $em->persist($newItem);
}

$em->flush();
rur96b6h

rur96b6h1#

根据这个答案,Doctrine2不允许您将多个INSERT语句组合成一个语句:
有些人似乎想知道为什么Doctrine不使用多插入(插入到(...)值(...),(...),(...),...
首先,只有mysql和更新的postgresql版本支持此语法。其次,当使用AUTO_INCREMENT或SERIAL时,没有简单的方法来获取在这种多插入中生成的所有标识符,并且ORM需要这些标识符来进行对象的标识管理。最后,插入性能很少是ORM的瓶颈。对于大多数情况来说,普通的插入已经足够快了,如果您真的想进行快速的批量插入,那么多次插入无论如何都不是最好的方法,例如Postgres COPY或Mysql LOAD DATA INFILE要快几个数量级。
这些就是为什么不值得在ORM中实现对mysql和postgresql执行多次插入的抽象的原因。
您可以在此处阅读更多有关Doctrine2批处理的信息:https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/batch-processing.html
您可以切换到DBAL,或者在插入一定数量的数据后刷新实体管理器,以小批量处理数据:

$batchSize = 20;

foreach ($items as $i => $item) {
     $product = new Product($item['datas']);

     $em->persist($product);

     // flush everything to the database every 20 inserts
     if (($i % $batchSize) == 0) {
         $em->flush();
         $em->clear();
    }
}

// flush the remaining objects
$em->flush();
$em->clear();
blpfk2vs

blpfk2vs2#

你可以试试这个fork https://github.com/stas29a/doctrine2。它实现的正是你想要的。我在MySQL中测试过它,它运行得很好,比批处理快5倍。这个fork获得第一个插入的id,并在php中递增它以获得其他id。它适用于大多数情况,但不是所有情况。所以你需要了解当你使用这个fork时你在做什么。

vngu2lb8

vngu2lb83#

您可以使用DriverConnection接口的executeUpdate($query, array $params = array(), array $types = array())方法来执行此操作。但是绑定多个参数有点麻烦。
数据来源:

$postMetaData = [
    [
        'post_id' => $product->getId(),
        'meta_key' => '_visibility',
        'meta_value' => 'visible',
    ],
    [
        'post_id' => $product->getId(),
        'meta_key' => '_stock_status',
        'meta_value' => $insert['in_stock'] ? 'instock' : 'outofstock',
    ]
];

批量更新方法:

public function updateOrCreateBulk($posts, \Doctrine\DBAL\Connection $connection)
{

    $placeholders = [];
    $values = [];
    $types = [];

    foreach ($posts as $columnName => $value) {
        $placeholders[] = '(?)';
        $values[] = array_values($value);
        $types[] = \Doctrine\DBAL\Connection::PARAM_INT_ARRAY;
    }

    return $connection->executeUpdate(
        'INSERT INTO `wp_postmeta` (`post_id`, `meta_key`, `meta_value`)  VALUES ' . implode(', ', $placeholders) . ' ON DUPLICATE KEY UPDATE `meta_value` = VALUES(`meta_value`)',
        $values,
        $types
    );
}
cidc1ykv

cidc1ykv4#

谢谢,现在我知道这是不可能的通过学说。
可以一次性使用
$em->merge($testCustomer);
则持久刷新
它将完美地工作

guz6ccqo

guz6ccqo5#

我还没有测试过,但似乎有可能用一个集合来做到这一点。

$collection = new Doctrine_Collection('tablename');
$collection->add($record1);
$collection->add($record2);
$collection->add($record3);
$collection->add($record4);
$collection->save();

当然,循环中应该有加法运算。

相关问题