【问题标题】:Doctrine2 findOneBy returning wrong resultDoctrine2 findOneBy 返回错误结果
【发布时间】:2016-06-03 22:28:58
【问题描述】:

我正在使用 Symfony2.3 和以下版本的教条组件(composer show -i | grep 教条)处理一个遗留项目:

doctrine/annotations                     v1.1.2 
doctrine/cache                           v1.2.0 
doctrine/collections                     dev-master bcb5377 
doctrine/common                          2.4.x-dev c94d6ff 
doctrine/data-fixtures                   dev-master 8ffac1c 
doctrine/dbal                            2.3.x-dev 59c310b 
doctrine/doctrine-bundle                 dev-master a41322d
doctrine/doctrine-fixtures-bundle        dev-master 3caec48
doctrine/doctrine-migrations-bundle      dev-master 1a7f58d 
doctrine/inflector                       dev-master 8b4b3cc
doctrine/lexer                           dev-master bc0e1f0
doctrine/migrations                      dev-master e960224 
doctrine/orm                             2.3.x-dev 66d8b43

我必须实现一个简单的数据库缓存系统。

我有一个存储表和一个服务类来访问它。 表架构如下:

CREATE TABLE `mlp_api_storage` (
    `id` TINYINT(4) NOT NULL AUTO_INCREMENT,
    `key` VARCHAR(250) NOT NULL,
    `value` TEXT NOT NULL,
    `is_serialized` TINYINT(4) NOT NULL,
    `created` DATETIME NOT NULL,
    `ttl` INT(11) NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `Index 2` (`key`)
)

我遇到的一个大问题是,当我尝试检索一个值时,我得到了错误的结果。 我正在跟踪日志文件,我可以看到正在使用正确的键值执行查询,如果我直接在 MySQL 中运行它,我将得到我期望的值,但不是教义。

这里是存储服务的相关代码:

/**
 * @param string $key
 * @param string $value
 * @param mixed $ttl
 * @return self
 */
public function set($key, $value, $ttl = null)
{
    $em     = $this->getEntityManager();
    $store  = $this->fetchEntity($key);
    $update = true;

    if (!$store) {
        $update = false;
        $store  = new Storage();
    }

    $store->setKey($key);

    if (is_object($value) || is_array($value)) {
        $value = serialize($value);
        $store->setIsSerialized(true);
    } else {
        $store->setIsSerialized(false);
    }

    $store->setValue($value);
    $store->setTtl($this->calculateTTL($ttl));
    $store->setCreated(new \DateTime());

    if ($update) {
        $em->merge($store);
    } else {
        $em->persist($store);
    }

    $em->flush($store);

    return $this;
}

       /**
         * @param string $key
         * @param mixed $default
         * @return string|null
         */
        public function fetch($key, $default = null)
        {
            $res = $this->fetchEntity($key);

            if ($res) {
                if ($this->isValidStorage($res)) {
                    $value = $res->getValue();

                    if ($res->getIsSerialized()) {
                        $value = unserialize($value);
                    }

                    return $value;
                }

                $this->remove($res);
            }

            if ($default) {
                $res = (is_callable($default)) ? $default($this) : $default;
            } else {
                $res = null;
            }

            return $res;
        }

        /**
         * @param string $key
         * @return Storage
         */
        private function fetchEntity($key)
        {
            /* @var $res Storage */
            $res = $this->getEntityManager()
                ->getRepository(Storage::class)
                ->findOneBy(['key' => $key]);

            if ($res) {
                return $res;
            }

            return null;
        }

所以使用调试器(和 mysql 日志)我可以看到一切都很好,直到以下行: ->findOneBy(['key' => $key]);

这将使用具有不同键和值的实体进行设置。

我已经设置了一个小例子:

$storage->set('test', '1111111111111111111');
$storage->set('test2', '22222222222222222222');
var_dump($storage->fetch('test'));
var_dump($storage->fetch('test2'));

这是返回:

字符串'1111111111111111111'(长度=19)

字符串'1111111111111111111'(长度=19)

这是表格中的内容:

这里是mysql的日志输出:

66 Query     SELECT t0.`key` AS key1, t0.value AS value2, t0.is_serialized AS is_serialized3, t0.created AS created4, t0.ttl AS ttl5, t0.id AS id6 FROM storage t0 WHERE t0.`key` = 'test' LIMIT 1
66 Query     SELECT t0.`key` AS key1, t0.value AS value2, t0.is_serialized AS is_serialized3, t0.created AS created4, t0.ttl AS ttl5, t0.id AS id6 FROM storage t0 WHERE t0.`key` = 'test2' LIMIT 1

我在教义2上做错了吗?我正在更新实体而不是删除,因为教义会在删除之前尝试插入。

谢谢!

更新:

这是实体代码

namespace PitchBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Storage
 *
 * @ORM\Table(name="storage")
 * @ORM\Entity
 */
class Storage
{
    /**
     * @var string
     *
     * @ORM\Column(name="`key`", type="string", length=250, nullable=false)
     */
    private $key;

    /**
     * @var string
     *
     * @ORM\Column(name="value", type="text", nullable=false)
     */
    private $value;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_serialized", type="boolean", nullable=false)
     */
    private $isSerialized;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="created", type="datetime", nullable=false)
     */
    private $created;

    /**
     * @var integer
     *
     * @ORM\Column(name="ttl", type="integer", nullable=true)
     */
    private $ttl;

    /**
     * @var boolean
     *
     * @ORM\Column(name="id", type="boolean")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * Set key
     *
     * @param string $key
     * @return Storage
     */
    public function setKey($key)
    {
        $this->key = $key;

        return $this;
    }

    /**
     * Get key
     *
     * @return string
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * Set value
     *
     * @param string $value
     * @return Storage
     */
    public function setValue($value)
    {
        $this->value = $value;

        return $this;
    }

    /**
     * Get value
     *
     * @return string
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Set isSerialized
     *
     * @param boolean $isSerialized
     * @return Storage
     */
    public function setIsSerialized($isSerialized)
    {
        $this->isSerialized = $isSerialized;

        return $this;
    }

    /**
     * Get isSerialized
     *
     * @return boolean
     */
    public function getIsSerialized()
    {
        return $this->isSerialized;
    }

    /**
     * Set created
     *
     * @param \DateTime $created
     * @return Storage
     */
    public function setCreated($created)
    {
        $this->created = $created;

        return $this;
    }

    /**
     * Get created
     *
     * @return \DateTime
     */
    public function getCreated()
    {
        return $this->created;
    }

    /**
     * Set ttl
     *
     * @param integer $ttl
     * @return Storage
     */
    public function setTtl($ttl)
    {
        $this->ttl = $ttl;

        return $this;
    }

    /**
     * Get ttl
     *
     * @return integer
     */
    public function getTtl()
    {
        return $this->ttl;
    }

    /**
     * Get id
     *
     * @return boolean
     */
    public function getId()
    {
        return $this->id;
    }
}

【问题讨论】:

  • 在上面的代码中似乎没有任何问题。您能否也显示Storage::class 的实体定义?这可能有助于复制。
  • @FrancescoAbeni 我已经添加了实体代码。
  • 另外,请出示完整的服务。我正在尝试重现,但缺少一些方法,其中一些可能是错误所在。
  • @FrancescoAbeni 您不再需要任何方法。只需忽略“isValidStorage”和“calculateTTL”,因为它们与错误无关。通过使用 xdebug 作为调试器,我可以看到,当我从教义中获取值时,它的实体是错误的。

标签: mysql symfony doctrine-orm


【解决方案1】:

您的实体id 注释中有错误。目前是:

 * @ORM\Column(name="id", type="boolean")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")

但应该是

 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")

【讨论】:

  • 哇!谢啦。我不知道为什么那是一个布尔值。该实体是由学说生成的,所以不太明白它是如何变成布尔值的。再次感谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多