如何使用Doctrine继承映射在子类上加载相关实体?

时间:2018-04-30 10:13:19

标签: symfony inheritance orm doctrine

Doctrine有几个很好的选择,可以为您的应用程序提供抽象和性能功能。

  1. 预取相关对象(通过加入它们)
  2. 实体模型中的继承映射
  3. 将两者结合起来似乎有点问题。我甚至不确定Doctrine是否能够处理这种程度的复杂性。 这将是我的问题真正存在的第三个讨论领域。

    1。预取相关对象:

    如果我只是想获取与RegularProduct相关的所有供应商实体,我会在我的存储库中执行类似的操作

    应用\库\ RegularProductRepository.php:

    namespace App\Repository;
    
    use Doctrine\ORM\EntityRepository;
    
    class RegularProductRepository extends EntityRepository
    {
        /**
         * @return array The result
         */
        public function findWithSupplier() : array
        {
            $alias = "rp";
    
            $qb = $this->createQueryBuilder($alias);
    
            $qb->addSelect("s"); // hydrates Supplier entity
            $qb->leftJoin($alias . ".supplier", "s");
    
            return $qb->getQuery()->getResult();
        }
    }
    

    这导致对数据库的单个查询。每当我在模板中读取供应商属性时,它都不需要再次查询数据库,因为供应商实体已经存储在ReguralProduct实体中。

    2。实体模型中的继承映射:

    在这个例子中,我向您展示了我在项目中实现的概念。

    应用\实体\ AbstractProductBase.php:

    namespace App\Entity;
    
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity(repositoryClass = "App\Repository\ProductBaseRepository")
     * @ORM\Table(name = "s4_product")
     * @ORM\MappedSuperclass
     * @ORM\InheritanceType("SINGLE_TABLE")
     * @ORM\DiscriminatorColumn(name = "product_type", type = "string")
     * @ORM\DiscriminatorMap({"RegularProduct" = "RegularProduct", "AliasedProduct" = "AliasedProduct"})
     */
    abstract class AbstractProductBase
    {
        /**
         * ID
         *
         * @var integer
         *
         * @ORM\Id
         * @ORM\Column(name = "product_id", type = "integer")
         * @ORM\GeneratedValue(strategy = "AUTO")
         */
        protected $id;
    
        /**
         * Name
         *
         * @var string
         *
         * @ORM\Column(name = "product_name", type = "string", length = 128)
         */
        protected $name;
    
        /**
         * Created At
         *
         * @var \DateTime
         *
         * @ORM\Column(name = "created_at_date", type = "datetime")
         */
        protected $createdAt;
    
        /**
         * Constructor
         */
        public function __construct()
        {
            $this->createdAt = new \DateTime();
        }
    
        /* ... getters & setters ... */
    }
    

    应用\实体\ RegularProduct.php:

    namespace App\Entity;
    
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\ORM\Mapping as ORM;
    
    use App\Entity\AliasedProduct;
    use App\Entity\ProductDevice;
    use App\Entity\Supplier;
    
    /**
     * @ORM\Entity(repositoryClass = "App\Repository\RegularProductRepository")
     */
    class RegularProduct extends AbstractProductBase
    {
        /**
         * Constructor
         */
        public function __construct()
        {
            parent::__construct();
    
            $this->aliasedProducts = new ArrayCollection();
            $this->devices         = new ArrayCollection();
        }
    
        /**
         * Supplier
         *
         * Many Products have one Supplier
         *
         * @var Supplier
         *
         * @ORM\ManyToOne(targetEntity = "Supplier", inversedBy = "products")
         * @ORM\JoinColumn(name = "supplier_id", referencedColumnName = "supplier_id")
         */
        protected $supplier;
    
        /**
         * Aliased Products
         *
         * One RegularProduct has Many AliasedProducts
         *
         * @var ArrayCollection
         *
         * @ORM\OneToMany(targetEntity = "AliasedProduct", mappedBy = "regularProduct")
         */
        protected $aliasedProducts;
    
        /**
         * Devices
         * 
         * Many Products have many Devices (with association class ProductDevice)
         * 
         * @var ArrayCollection
         *
         * @ORM\OneToMany(targetEntity = "ProductDevice", mappedBy = "product", cascade = { "persist", "remove" })
         */
        protected $devices;
    
        /**
         * Set supplier
         *
         * @param \App\Entity\Supplier $supplier
         * @return RegularProduct
         */
        public function setSupplier(Supplier $supplier = null)
        {
            $this->supplier = $supplier;
    
            return $this;
        }
    
        /**
         * Get supplier
         *
         * @return \App\Entity\Supplier
         */
        public function getSupplier()
        {
            return $this->supplier;
        }
    
        /**
         * Add aliasedProduct
         *
         * @param \App\Entity\AliasedProduct $aliasedProduct
         * @return RegularProduct
         */
        public function addAliasedProduct(AliasedProduct $aliasedProduct)
        {
            $aliasedProduct->setRegularProduct($this);
    
            $this->aliasedProducts[] = $aliasedProduct;
    
            return $this;
        }
    
        /**
         * Remove aliasedProduct
         *
         * @param \App\Entity\AliasedProduct $aliasedProduct
         */
        public function removeCopy(AliasedProduct $aliasedProduct)
        {
            $this->aliasedProducts->removeElement($aliasedProduct);
        }
    
        /**
         * Get aliasedProducts
         *
         * @return \Doctrine\Common\Collections\Collection
         */
        public function getAliasedProducts()
        {
            return $this->aliasedProducts;
        }
    
        /**
         * Add device
         *
         * @param \App\Entity\ProductDevice $device
         *
         * @return Product
         */
        public function addDevice(ProductDevice $device)
        {
            $device->setProduct($this);
    
            $this->devices[] = $device;
    
            return $this;
        }
    
        /**
         * Remove device
         *
         * @param \App\Entity\ProductDevice $device
         */
        public function removeDevice(ProductDevice $device)
        {
            $this->devices->removeElement($device);
        }
    
        /**
         * Get devices
         *
         * @return \Doctrine\Common\Collections\Collection
         */
        public function getDevices()
        {
            return $this->devices;
        }
    }
    

    应用\实体\ AliasedProduct.php:

    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    
    use App\Entity\AbstractProductBase;
    use App\Entity\RegularProduct;
    
    /**
     * Aliased Product Entity
     *
     * @ORM\Entity()
     */
    class AliasedProduct extends AbstractProductBase
    {
        /**
         * Constructor
         */
        public function __construct()
        {
            parent::__construct();
        }
    
        /**
         * Regular Product
         *
         * Many AliasedProducts have one RegularProduct
         *
         * @var \App\Entity\RegularProduct
         *
         * @ORM\ManyToOne(targetEntity = "RegularProduct", inversedBy = "aliasedProducts", fetch = "EXTRA_LAZY")
         * @ORM\JoinColumn(name = "original_product_id", referencedColumnName = "product_id")
         */
        protected $regularProduct;
    
        /**
         * Set regularProduct
         *
         * @var \App\Entity\RegularProduct
         *
         * @return AliasedProduct
         */
        public function setRegularProduct(RegularProduct $regularProduct = null)
        {
            $this->regularProduct = $regularProduct;
    
            return $this;
        }
    
        /**
         *
         * @return \App\Entity\RegularProduct
         */
        public function getRegularProduct()
        {
            return $this->regularProduct;
        }
    
        /**
         * Get supplier
         *
         * @return Supplier
         */
        public function getSupplier()
        {
            return $this->regularProduct->getSupplier();
        }
    }
    

    3。在继承的类上保护相关实体

    当我想在具有继承映射的类上实现这一点时,似乎我还需要加入Sub实体RegularProduct 在我的结果集中将是RegularProduct和AliasedProduct实体。

    在下面的Repository中执行查询会导致HydrationException,并显示消息:The parent object of entity result with alias 'd' was not found. The parent alias is 'rp'.

    应用\库\ ProductBaseRepository.php:

    namespace App\Repository;
    
    use Doctrine\ORM\EntityRepository;
    use App\Entity\RegularProduct;
    
    abstract class ProductBaseRepository
    {
        /**
         * @return array
         */
        public function getAllWithDevices() : array
        {
            $alias = "pb"; // AbstractProductBase
    
            $qb->leftJoin(
                RegularProduct::class,
                "rp",
                "WITH",
                $qb->expr()->eq($alias,"p")
            );
    
            $qb->addSelect("d"); // hydrates ProductDevice entity
    
            $qb->leftJoin(
                "rp.devices",
                "d",
                "WITH",
                $qb->expr()->eq("rp", "d.product")
            );
    
            return $qb->getQuery()->getResult();
        }
    }
    

    我尝试通过添加$qb->addSelect("rp")来更改查询。这解决了获得异常但提出了一个新问题;结果不干净。 此时,结果数组包含所有RegularProducts两次,AliasedProducts一次,并且对于每个AliasedProduct,都有一个null变量。

    是否可以通过任何方式执行仅在我的代码中添加$qb->addSelect("rp")行而不在常规产品上保存设备的查询?

0 个答案:

没有答案