Rob*_*est 13 php object doctrine-orm doctrine-extensions
我正在寻求提高学说水合的速度.我以前一直在使用,HYDRATE_OBJECT但可以看到,在许多情况下,使用它可能会非常繁重.
我知道可用的最快的选项是HYDRATE_ARRAY,然后我提供了使用实体对象的许多好处.在实体方法中存在业务逻辑的情况下,这将被重复,但是由数组处理.
所以我所追求的是更便宜的物体保湿剂.我很高兴以速度的名义做出一些让步并放松一些功能.例如,如果它最终只是被读取,那就没问题了.同样,如果延迟加载不是一件事,那也没关系.
这种事情是存在还是我要求太多?
Mar*_*ulc 14
如果你想要更快ObjectHydrator而不失去使用物体的能力,那么你将不得不创建自己的定制保湿器.
为此,您必须执行以下步骤:
创建自己的Hydrator扩展类Doctrine\ORM\Internal\Hydration\AbstractHydrator.在我的情况下,我正在扩展,ArrayHydrator因为它省去了将别名映射到对象变量的麻烦:
use Doctrine\ORM\Internal\Hydration\ArrayHydrator;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use PDO;
class Hydrator extends ArrayHydrator
{
const HYDRATE_SIMPLE_OBJECT = 55;
protected function hydrateAllData()
{
$entityClassName = reset($this->_rsm->aliasMap);
$entity = new $entityClassName();
$entities = [];
foreach (parent::hydrateAllData() as $data) {
$entities[] = $this->hydrateEntity(clone $entity, $data);
}
return $entities;
}
protected function hydrateEntity(AbstractEntity $entity, array $data)
{
$classMetaData = $this->getClassMetadata(get_class($entity));
foreach ($data as $fieldName => $value) {
if ($classMetaData->hasAssociation($fieldName)) {
$associationData = $classMetaData->getAssociationMapping($fieldName);
switch ($associationData['type']) {
case ClassMetadataInfo::ONE_TO_ONE:
case ClassMetadataInfo::MANY_TO_ONE:
$data[$fieldName] = $this->hydrateEntity(new $associationData['targetEntity'](), $value);
break;
case ClassMetadataInfo::MANY_TO_MANY:
case ClassMetadataInfo::ONE_TO_MANY:
$entities = [];
$targetEntity = new $associationData['targetEntity']();
foreach ($value as $associatedEntityData) {
$entities[] = $this->hydrateEntity(clone $targetEntity, $associatedEntityData);
}
$data[$fieldName] = $entities;
break;
default:
throw new \RuntimeException('Unsupported association type');
}
}
}
$entity->populate($data);
return $entity;
}
}
Run Code Online (Sandbox Code Playgroud)在Doctrine配置中注册水化器:
$config = new \Doctrine\ORM\Configuration()
$config->addCustomHydrationMode(Hydrator::HYDRATE_SIMPLE_OBJECT, Hydrator::class);
Run Code Online (Sandbox Code Playgroud)AbstractEntity使用填充实体的方法创建.在我的示例中,我使用已在实体中创建的setter方法来填充它:
abstract class AbstractEntity
{
public function populate(Array $data)
{
foreach ($data as $field => $value) {
$setter = 'set' . ucfirst($field);
if (method_exists($this, $setter)) {
$this->{$setter}($value);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)这三个步骤后,你可以通过HYDRATE_SIMPLE_OBJECT替代HYDRATE_OBJECT来getResult查询方法.请记住,这个实现没有经过严格测试,但是即使使用嵌套映射也可以使用更高级的功能,你必须改进它Hydrator::hydrateAllData(),除非你实现与你的连接,否则EntityManager将失去轻松保存/更新实体的能力,而另一方面因为这些对象只是简单的对象,您将能够序列化和缓存它们.
测试代码:
$hydrators = [
'HYDRATE_OBJECT' => \Doctrine\ORM\AbstractQuery::HYDRATE_OBJECT,
'HYDRATE_ARRAY' => \Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY,
'HYDRATE_SIMPLE_OBJECT' => Hydrator::HYDRATE_SIMPLE_OBJECT,
];
$queryBuilder = $repository->createQueryBuilder('u');
foreach ($hydrators as $name => $hydrator) {
$start = microtime(true);
$queryBuilder->getQuery()->getResult($hydrator);
$end = microtime(true);
printf('%s => %s <br/>', $name, $end - $start);
}
Run Code Online (Sandbox Code Playgroud)
结果基于940条记录,每条记录20~列:
HYDRATE_OBJECT => 0.57511210441589
HYDRATE_ARRAY => 0.19534111022949
HYDRATE_SIMPLE_OBJECT => 0.37919402122498
Run Code Online (Sandbox Code Playgroud)
您可能正在寻找Doctrine混合DTO(数据传输对象)的方法。这些不是真实的实体,而是用于传递数据的简单只读对象。
从Doctrine 2.4开始,它使用NEWDQL中的运算符为此类水合提供了本机支持。
当您有这样的课程时:
class CustomerDTO
{
private $name;
private $email;
private $city;
public function __construct($name, $email, $city)
{
$this->name = $name;
$this->email = $email;
$this->city = $city;
}
// getters ...
}
Run Code Online (Sandbox Code Playgroud)
您可以这样使用SQL:
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city) FROM Customer c JOIN c.email e JOIN c.address a');
$customers = $query->getResult();
Run Code Online (Sandbox Code Playgroud)
$customers然后将包含一个CustomerDTO对象数组。
您可以在文档中找到它。
| 归档时间: |
|
| 查看次数: |
4585 次 |
| 最近记录: |