symfony - 如何使用 Doctrine 继承映射在子类上加载相关实体?
问题描述
Doctrine 有几个很好的选择来为你的应用程序提供抽象和性能特性。
- 预取相关对象(通过加入它们)
- 实体模型中的继承映射
将两者结合起来似乎有点问题。我什至不确定 Doctrine 是否能够处理这种规模的复杂性。这将是我的问题真正所在的第三个讨论领域。
1、预取相关对象:
如果我只是想获取与 RegularProduct 相关的所有供应商实体,我会在我的存储库中执行类似的操作
App\Repository\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 ... */
}
应用\实体\常规产品.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;
}
}
应用\实体\别名产品.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.在继承类上水合相关实体
当我想在具有继承映射的类上实现这一点时,似乎我还需要加入子实体 RegularProduct 在我的结果集中将是 RegularProduct 和 AliasedProduct 实体。
在下面的存储库中执行查询会导致 HydrationException 并显示以下消息:The parent object of entity result with alias 'd' was not found. The parent alias is 'rp'.
App\Repository\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 都有一个空变量。
是否可以通过任何方式执行仅在RegularProducts 上补充Devices 而不$qb->addSelect("rp")
在我的代码中添加该行的查询?
解决方案
推荐阅读
- git - Is it possible to reference Git objects from a commit without adding them to the tree-object filesystem?
- laravel - Modify Breeze template in Laravel
- javascript - Onclick only works on second click. How to get it to work on first click
- input - 如何设置 Yii2 ajaxCrud modal 的 activeform 输入字段自动对焦
- dataframe - 如何在 pyspark 数据框中拆分数字并添加连字符?
- selenium - 如何使用 SendKeys Selenium 上传多个文件
- ruby-on-rails - 为什么 Rails 缓存过期不起作用?
- amazon-web-services - EC2 服务器实例上的 Amazon ECS 命中 RESOURCE:ENI 错误
- npm - Gitlab NPM 注册表安装 503
- node.js - 如何从 Firebase 托管重写发送的请求中获取 Cloud Run 服务器上的主机名?