【问题标题】:Symfony2 ManyToMany in one querySymfony2 多对多在一个查询中
【发布时间】:2017-11-05 14:03:26
【问题描述】:

我有 2 个与多对多相关的实体

class Product
{

/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=100, unique=true)
 */
private $name;

/**
 * @ORM\ManyToMany(targetEntity="ProductTransfer", inversedBy="product")
 * @ORM\JoinTable(name="products_transfers")
 */
private $transfers;

第二个

class ProductTransfer
{
/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var int
 *
 * @ORM\Column(name="stock_from_id", type="integer")
 */
private $stockFromId;

/**
 * @var int
 *
 * @ORM\Column(name="stock_to_id", type="integer")
 */
private $stockToId;

/**
 * @var int
 *
 * @ORM\Column(name="product_id", type="integer")
 */
private $productId;

/**
 * @ORM\ManyToMany(targetEntity="Product",mappedBy="transfers")
 */
private $product;

一切都很好,额外的表格是由 Doctrine 创建的。
但是,当我尝试从 ProductTransfers 获取所有行时,我在分析器中看到每一行都需要一个带有 2 个连接的查询。
因此,对于 5000 种产品,这将是非常多的查询。

有没有办法像“干净的 SQL”一样在一个查询中获取它们? 如果 Doctrine 无法做到这一点,那么实现这一目标的最佳方法是什么?

喜欢:

SELECT * FROM product_transfer pt
LEFT JOIN products_transfers pts ON pt.product_id=pts.product_id
LEFT JOIN product p ON pts.product_id=p.id;

编辑: 在存储库中创建方法

public function loadTransfersByStock($stockId)
{

    $q = $this->getEntityManager()
        ->createQuery(
            'SELECT pt,p FROM AppBundle:ProductTransfer pt
            LEFT JOIN AppBundle:Product p WITH pt.productId=p.id
            WHERE pt.stockToId = :stockId'
        );

    return $q->setParameter('stockId', $stockId)->getResult();
}

然后结果是

ProductsController.php on line 495:
array:3 [▼
  0 => ProductTransfer {#1071 ▶}
  1 => Product {#1084 ▶}
  2 => ProductTransfer {#1099 ▶}
]

【问题讨论】:

  • 是的,只需加入您需要的关系,显示查询,不清楚您使用的是查询构建器还是 dql
  • @JimL 我正在使用 entityManager 和存储库来获取它们,所以我应该使用自定义 SQL 查询?
  • 您应该在存储库中创建自己的方法并使用查询生成器或 dql,无论您喜欢哪种方式
  • @JimL 我添加到我在回购中创建的问题方法中,但仍然相同......
  • 在查询生成器/dql 中使用关系。 join pt.product,它似乎依赖于使用命名关系(来自实体)来正确地做到这一点。顺便说一句,在多对多关系中,如果该关系也是复数(它来自另一边),那将是有意义的

标签: php mysql symfony doctrine-orm entity-relationship


【解决方案1】:

默认情况下,Doctrine 在对象关系中使用延迟加载——关系的行仅在您尝试访问它们时才会加载。如果您知道您将需要所有相关行,请尝试更改为急切获取。

/**
 * @ORM\ManyToMany(targetEntity="ProductTransfer", inversedBy="product", fetch="EAGER")
 * @ORM\JoinTable(name="products_transfers")
 */

【讨论】:

  • @Kaivisukeltaja 添加,没有任何结果
  • @rafwlaz,它需要添加到您用作入口点的实体中 - 尝试将其添加到另一个?
  • @Kaivisukeltaja 我按照对我的问题的评论中所写的方法修复它,现在一切正常
【解决方案2】:

当您在存储库中编写这样的查询时,您正在跳过学说“希望”您编写它的方式。因此,我会做这样的事情,而不是那样:

//ProductTransferRepository.php
$qb = $this->createQueryBuilder('pt');
$qb
    ->select('pt, p') // here you can choose the columns you want if you don't need everything from both tables
    ->leftJoin('pt.product', 'p')
    ->where('pt.stockToId = :stockId')
    ->setParameter('stockId', $stockId)
;
return $qb
    ->getQuery()
    ->getArrayResult()
;

使用getArrayResult 以数组而不是对象的形式获取结果,尤其是因为您有很多查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多