Doctrine有几个很好的选择,可以为您的应用程序提供抽象和性能功能。
将两者结合起来似乎有点问题。我甚至不确定Doctrine是否能够处理这种程度的复杂性。 这将是我的问题真正存在的第三个讨论领域。
如果我只是想获取与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实体中。
在这个例子中,我向您展示了我在项目中实现的概念。
应用\实体\ 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();
}
}
当我想在具有继承映射的类上实现这一点时,似乎我还需要加入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")
行而不在常规产品上保存设备的查询?