尝试使用Symfony创建一个查询,允许我访问外键对象

时间:2017-08-23 22:28:43

标签: php mysql symfony doctrine dql

所以我有3个实体:

超市:

| id | supermarket_name |

分类

| id | category_name |

产品:

| id | product_name | supermarket_id | category_id |

supermarket_id和category_id分别与超市和类别的ID分别为多对一。

我希望这样当我选择一家超市时,我会获得该超市下面列出的所有类别。我一直试图通过我的ProductRepository.php文件中传递到查询方法的超市ID从产品实体获取此数据,如果我有以下内容,该数据会成功运行:

public function findAllCategoriesBySupermarket($supermarketId)
    {
        return $this->getEntityManager()
            ->createQuery(
                "SELECT p
                FROM AppBundle:Product p
                WHERE p.supermarketId = $supermarketId"
            )
            ->getResult();
    }

然后,我可以在我的视图中成功地在循环中显示产品:

{{ product.categoryId.categoryName }}

问题是因为我从产品中查询我将最终得到多个相同类别的产品,因为可以将多个产品分配到同一类别,因此我尝试通过向该类别添加distinct来解决此问题:

public function findAllCategoriesBySupermarket($supermarketId)
    {
        return $this->getEntityManager()
            ->createQuery(
                "SELECT DISTINCT p.categoryId
                FROM AppBundle:Product p
                WHERE p.supermarketId = $supermarketId"
            )
            ->getResult();
    }

当我在phpmyadmin中测试它时,这很好用,但不幸的是symfony给出了以下错误:

[Semantical Error] line 0, col 18 near 'categoryId
': Error: Invalid PathExpression. Must be a StateFieldPathExpression.

我不知道如何解决这个问题,因为我已经尝试了很多不同的事情而没有运气。关于如何解决这个问题的任何建议都将不胜感激!

1 个答案:

答案 0 :(得分:0)

问题是您无法在学说中按属性选择不同的实体关联。但是,您可以选择不同的身份。假设您想要实体而不仅仅是ID ......

要实现此目的,您需要将两个实体之间的关联定义为双向。

由于您在Product.category上有关联,但与Category.products关联,因此您需要创建关联。

/**
 * @ORM\Entity
 */
class Category 
{
   //...

   /**
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\Product", mappedBy="category")
    */
   private $products;


    public function __construct()
    {
         $this->products = new \Doctrine\Common\Collections\ArrayCollection;
    }

    //...

   /**
    * get Products
    * @return Product[]|ArrayCollection
    */
    public function getProducts()
    {
        return $this->products;
    }

     /**
      * add Product
      * @param Product $product
      * @return $this
      */
     public function addProduct(Product $product)
     {
        $this->products->add($product);

         return $this;
     }

    /**
     * remove Product
     * @param Product $product
     * @return $this
     */
    public function removeProduct(Product $product)
    {
        $this->products->removeElement($product);

        return $this;
    }
}

然后在inversedBy属性

中添加关联Product.category
/**
 * @ORM\Entity
 */
class Product
{

    //...

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="products")
     * @ORM\JoinColumn(name="category", referencedColumnName="id")
     */
    private $category;

    //...
}

如果没有根关联,您也无法选择关联的实体。 例如

SELECT DISTINCT c
FROM AppBundle:Product p
JOIN p.category c
  

'SELECT DISTINCT':错误:如果不选择至少一个根实体别名,则无法通过标识变量选择实体。

因此,要检索产品与指定超市相关联的不同类别,您可以像这样编写DQL。

public function findAllCategoriesBySupermarket($supermarketId)
{
    return $this->_em->createQuery(
            'SELECT c
            FROM AppBundle:Category c
            JOIN c.products p WITH p.supermarketId = :supermarket'
        )
        ->setParameter('supermarket', $supermarketId)
        ->getResult();
}

虽然我想指出,DISTINCT标志在此上下文中是多余的,因为仅选择类别(c)是隐含的。

您也可以使用SELECT c, p来获取包含相关产品的类别数组。

{% for category in categories %}
    {{ category.name }}:
    {% for product in category.products %}
        {{ product.name }}
    {% endfor %}
{% endfor %}

或者,为了保留单向关系,您需要使用子查询。但是如上所示,您将失去检索Category.products关联的能力。

SELECT c
FROM AppBundle:Category c
WHERE c.id IN (
    SELECT DISTINCT IDENTITY(p.categoryId)
    FROM AppBundle:Product p
    WHERE p.supermarketId = :supermarket
)