Symfony学说并没有使整个链条水合



我在下面尽可能简化了我的3个实体,它显示了Currency <- 1:1 -> Balance <- 1:N -> BalanceLog的简单关系

实体/Currency.php

/**
* @ORMEntity(repositoryClass=CurrencyRepository::class)
*/
class Currency
{
/**
* @ORMId
* @ORMColumn(type="string", length=3)
*/
private ?string $code;

/**
* @ORMOneToOne(targetEntity="Balance", mappedBy="currency")
**/
private ?Balance $balance;
// ...
}

实体/余额.php

/**
* @ORMEntity(repositoryClass=BalanceRepository::class)
*/
class Balance
{
/**
* @ORMId
* @ORMOneToOne(targetEntity="Currency", inversedBy="balance")
* @ORMJoinColumn(name="currency", referencedColumnName="code", nullable=false)
**/
private ?Currency $currency;

/**
* @ORMOneToMany(targetEntity="AppEntityBalanceLog", mappedBy="balance")
*/
private Collection $balance_logs;
// ...
}

实体/余额日志.php

/**
* @ORMEntity(repositoryClass=BalanceLogRepository::class)
*/
class BalanceLog
{
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private ?int $id;
/**
* @ORMManyToOne(targetEntity="AppEntityBalance", inversedBy="balance_logs")
* @ORMJoinColumn(name="balance_currency", referencedColumnName="currency")
**/
private ?Balance $balance;
// ...
}

问题发生在我打电话时:

$balanceLog = $this->getDoctrine()
->getRepository('App:BalanceLog')->findAll();

这将BalanceLog::$balance水合为Balance类型的适当实例,但不会将BalanceLog::$balance->currency水合为Currency实例。相反,它希望只使用string

导致错误:

类型属性App\Entity\Balance::$currency必须是App\Entity\currency的实例或null,字符串使用

脏修复是在没有固定类型?Currency的情况下使Balance::$currency。然后它将接受字符串;作品";。但这是不对的。Balance::$currency应该是Currency类型,有时不是字符串,有时是货币。

我试着在BalanceLogRepository中制作自己的方法,无论出于什么原因,这都很好:

public function findByBalance(Balance $balance) : iterable
{
$query = $this->createQueryBuilder('bl');
$query->andWhere('bl.balance = :balance')
->setParameter('balance', $balance);
return $query->getQuery()->getResult();
}

因此,我更困惑的是,为什么默认的findAllfindBy不进行递归水合

经过进一步调查,我发现了一个非常奇怪的行为:

如果我准备这个代码:

$balance = $this->getDoctrine()->getRepository('App:Balance')->find('USD');

在前面

$balanceLog = $this->getDoctrine()->getRepository('App:BalanceLog')->findAll();

在我的控制器中,错误消失。就好像Balance的具有依赖关系的App:BalanceORM模式没有正确加载,直到我尝试直接从先验中获取Balance对象。

我做了一些调试,看起来BalanceLog并没有创建一个完整的Balance实体实例,而是创建了一个代理。解决方案是在BalanceLog类中添加紧急加载

class BalanceLog
{
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private ?int $id;
/**
* @ORMManyToOne(targetEntity="AppEntityBalance", inversedBy="balance_logs", fetch="EAGER")
* @ORMJoinColumn(name="balance_currency", referencedColumnName="currency")
**/
private ?Balance $balance;
// ...
}

UnitOfWork.php则不使用Proxy,而是将实体作为一个整体加载。

如果有人想知道为什么事先查询Balance使代码工作,那是因为Doctrine的复杂缓存机制。它为主键USD保存了Balance实例,然后在填充BalanceLog时,它使用该实例而不是创建代理。

我仍然认为Proxy不应该从Entity强制执行严格类型的属性,但这是由Doctrine开发者决定的。

相关内容

  • 没有找到相关文章

最新更新