我有以下问题:
教义假设更新被改变的实体。问题是,由于某种原因(也许是遗留的 32 位系统?(,bigint 数据类型被视为字符串(如下所示 - 这是 doctrine 中的 bigint 类型类,在 doctrine 代码中还有多个其他字符串的转换(。
<?php
namespace DoctrineDBALTypes;
use DoctrineDBALParameterType;
use DoctrineDBALPlatformsAbstractPlatform;
/**
* Type that maps a database BIGINT to a PHP string.
*/
class BigIntType extends Type implements PhpIntegerMappingType
{
/**
* {@inheritdoc}
*/
public function getName()
{
return Type::BIGINT;
}
/**
* {@inheritdoc}
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration);
}
/**
* {@inheritdoc}
*/
public function getBindingType()
{
return ParameterType::STRING;
}
/**
* {@inheritdoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value === null ? null : (string) $value;
}
}
这会导致更新不应更新的数据,因为工作单元检查器将数据比较为严格(应有(,从而导致差异(下面的代码(。
// skip if value haven't changed
if ($orgValue === $actualValue) { // $orgValue = "3829784117300", $actualValue = 3829784117300
continue;
}
这样做的最终结果是以下代码:
$product = $productRepo->find($id);
$product->setOwnerId($ownerId); // $ownerId = 3829784117300
$this->em->flush();
正在生成一个查询,该查询执行...除了强调数据库之外,基本上什么都没有(就我而言,我每天有几千万个(。上述特定情况的解决方案...
$product = $productRepo->find($id);
if ((int)$product->getOwnerId() !== $ownerId) {
$product->setOwnerId($ownerId); // $ownerId = 3829784117300
}
$this->em->flush();
简单吧?但。。。当你有 2 个 bigint 时,你会怎么做?还行。。。2 条件...没什么大不了的。但是,如果他们是...90?还行。。。我们可以使用反射遍历实体属性并全部选中。
但。。。如果关系链中的某个地方有另一个实体需要检查怎么办?完整的解决方案是,我们必须递归地检查实体及其子级的每个属性,并检查 bigint。
但。。。这不就是教义工作单元的目的吗?为什么我需要重新解析整个实体并检查已经检查的内容,因为 bigint 被视为字符串(导致基本上复制了一大块教义代码(?
现在的问题...如何解决这个问题(请记住,我不是在为一个简单的情况要求特定的解决方案,我要求一个通用的解决方案,可以应用于应该在未来几年内使用的大型代码库 - 正如你在上面看到的,我有解决方案,但我不能接受一半的工作和脆弱的代码,除非真的没有其他方法(?我正在寻找一个我错过的设置,它使教义将整数视为整数而不是字符串......诸如此类的东西。
一种解决方案是用你自己的类型覆盖 Doctrine 对bigint
类型的实现。首先,创建一个与 DoctrineBigIntType
相同的类,除了将 cast 替换为 cast to int:
class MyBigIntType extends Type
{
/**
* {@inheritdoc}
*/
public function getName()
{
return Type::BIGINT;
}
/**
* {@inheritdoc}
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration);
}
/**
* {@inheritdoc}
*/
public function getBindingType()
{
return PDO::PARAM_STR;
}
/**
* {@inheritdoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (null === $value) ? null : (int)$value;
}
}
然后,在config.yml
或doctrine.yaml
中注册类型:
doctrine:
dbal:
types:
bigint: MyBigIntType
我用 Symfony 2.8 对此进行了测试,这导致对类型为bigint
的所有字段使用MyBigIntType
。也应该适用于以后的Symfony版本。