首页  >  问答  >  正文

ULID 在数据库中错误地存储为 UUID(vanilla symfony 应用程序)

昨天我尝试做 Symfony 在一些博客文章中喊出的事情(https://symfony.com/blog/new-in-symfony-5-2-doctrine-types-for-uuid-and-ulid)但是失败了。我想在数据库中存储 ULID(格式“TTTTTTTTTTRRRRRRRRRRRRRRRR”),因为它们不仅可以排序,而且还包含一个非常适合我的应用程序的时间戳。但是,当我告诉属性为“type=ulid”时,它将作为 UUID(格式:“xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx”)存储在数据库中。

我调试了半天,对此很恼火,我从头开始,问题仍然存在。

我哪里出错了?

(如果您愿意,请跳到 ULID 标题,以下内容可能看起来很长,但其中 50% 只是基本内容)

交响乐

我一遍又一遍地做的事情取自https://symfony.com/doc/5.4/setup.html:

  1. stat shyt # 不存在
  2. composer 创建项目 symfony/sculpture:5.4.* shyt
  3. cd shyt;作曲家需要 webapp
  4. 您想包含食谱中的 Docker 配置吗?是(默认)
  5. bin/console about 显示 Symfony 版本 5.4.10 和 PHP 7.4

ORM

取自https://symfony.com/doc/5.4/doctrine.html:

  1. composer 需要 symfony/orm-pack
  2. composer 需要 --dev symfony/maker-bundle
  3. docker-compose up -d

错误:在分配给网络的默认地址池中找不到可用的、不重叠的 IPv4 地址池

所以我在 docker-compose.override.yml 文件中添加了一些行:

networks:
  default:
    ipam:
      config:
        - subnet: 10.1.2.1/24

services:
  database:
  # [...] doctrine/doctrine-bundle stuff [...]
  networks:
    default:
      ipv4_address: 10.1.2.3
  1. 在“.env”中为主机“10.1.2.3”设置 DATABASE_URL
  2. bin/console 学说:数据库:create(很愚蠢,但如文档所述)

无法为名为default的连接创建数据库“app” 执行查询时发生异常:SQLSTATE[42P04]:重复数据库:7错误:数据库“app”已存在

嗯,是的。 Docker 已经做到了这一点。

  1. make:entity 被推迟,直到我们拥有 ULID 功能。

ULID

我们已经倾向于 https://symfony.com/doc/5.4/components/uid.html (尤其是 ULID 部分):

  1. composer 需要 symfony/uid
  2. bin/console make:entity Product
  1. 检查产品实体

看起来几乎与文档中的一样,只是它有一个附加字段(主键,一个整数)和一些 getter/setter。

  1. bin/console make:migration

测试 ULID 实体

在这之间,我们使用测试以编程方式创建数据库条目:

  1. composer 需要 phpunit 以编程方式创建数据库条目
  2. bin/console --env=测试主义:migrations:migrate
  3. bin/console --env=测试主义:数据库:create
  4. 文件“tests/FooTest.php”包含:
<?php

namespace AppTests;

use AppEntityProduct;
use AppRepositoryProductRepository;
use DoctrineORMEntityManager;
use SymfonyBundleFrameworkBundleTestKernelTestCase;
use SymfonyComponentUidUlid;

class FooTest extends KernelTestCase
{
    public function testFoo(): void
    {
        $product = new Product();
        $product->setSomeProperty(new Ulid());
        static::assertNotNull($product->getSomeProperty());

        self::getContainer()->get(ProductRepository::class)
            ->add($product);

        self::getContainer()->get('doctrine.orm.entity_manager')
            ->flush();
    }
}
  1. bin/console --env=test 主义:query:sql 'TRUNCATE Product' 只是为了确定
  2. bin/phpunit
  3. bin/console --env=测试主义:query:sql 'SELECT * FROM 产品'

显示 UUID,而不是 ULID。

在数据库中显示 ULID 而不是 UUID

使用 ULID 作为主键

首先清理一下,然后执行 https://symfony.com/doc/5.4/components/uid.html#ulids 中所示的示例:

  1. rm 迁移/* 重新开始
  2. bin/console --env=测试主义:database:drop --force
  3. bin/console --env=测试主义:数据库:create
  4. bin/控制台主义:数据库:drop --force
  5. bin/console --env=测试主义:数据库:create
  6. 编辑“src/Entity/Product.php”以仅包含文档中的第二个 ULID 示例:
<?php

namespace AppEntity;

use DoctrineORMMapping as ORM;
use SymfonyComponentUidUlid;
use AppRepositoryProductRepository;

/**
 * @ORMEntity(repositoryClass=ProductRepository::class)
 */
class Product
{
    /**
     * @ORMId
     * @ORMColumn(type="ulid", unique=true)
     * @ORMGeneratedValue(strategy="CUSTOM")
     * @ORMCustomIdGenerator(class="doctrine.ulid_generator")
     */
    private $id;

    public function getId(): ?Ulid
    {
        return $this->id;
    }

    // ...

}

(文档中的示例缺少存储库行)

  1. bin/console make:migration
  2. bin/console --env=测试主义:migrations:migrate
  3. 测试现在更简单了:
public function testFoo(): void
    {
        self::getContainer()->get(ProductRepository::class)
            ->add(new Product());

        self::getContainer()->get('doctrine.orm.entity_manager')
            ->flush();
    }
  1. bin/phpunit(有风险也可以)
  2. bin/console --env=测试主义:query:sql 'SELECT * FROM 产品'

再次使用 UUID 而不是 ULID

数据库显示 UUID 而不是 ULID

P粉381463780P粉381463780332 天前608

全部回复(1)我来回复

  • P粉377412096

    P粉3774120962023-12-17 00:06:49

    有点晚了,但对于面临这个问题的人来说,我也有显示 UUID 而不是 ULID 的数据库,这似乎是学说中的预期行为,因为您可以互换使用 UUID/ULID,这意味着即使您将 UUID 存储在数据库,但您的实体映射到 ULID,从数据库检索对象时您将拥有 ULID,您也可以使用 ULID 或 UUID 检索相同的对象。

    例如,我有一个用户实体,其标识符具有 ULID,因此存储的对象将具有如下 uuid:

    018477e6-eebc-164c-12e3-22ca8f1a88f3    myemail@mail.com    []

    如果我使用该 UUID 检索我的用户,我将得到:

    App\Entity\User {#430 ▼
     -id: "01GHVYDVNW2S615RS2SA7HN27K"
     -email: "myemail@mail.com"
     -roles: []
     #createdAt: DateTime @1668458933 {#423 ▶}
     #updatedAt: DateTime @1668458998 {#428 ▶}
     -password: "y$/2i9Ovc2lCQBRfSVgsnmoul1FhF.Kyki3irF6GQvrMrjacQX6ees6"
     -isVerified: true
    }

    现在,如果您使用该 ULID 来检索您的用户,它也将起作用!

    如果您检查该 UUID,您会发现返回的对象已将该 uuid 转换为基数 32:

    bash-5.1$ bin/console uuid:inspect 018477e6-eebc-164c-12e3-22ca8f1a88f3
    ----------------------- --------------------------------------
    Label                   Value
    ----------------------- --------------------------------------
    Version                 1                                     
      toRfc4122 (canonical)   018477e6-eebc-164c-12e3-22ca8f1a88f3  
      toBase58                1BsMRvKcgozP4Kw2m4Fb1C                
      toBase32                01GHVYDVNW2S615RS2SA7HN27K
    ----------------------- --------------------------------------

    最后,您可以通过将其转换为 refc4122 来获取存储的 uuid,如下所示:

    bin/console ulid:inspect 01GHVYDVNW2S615RS2SA7HN27K
    ---------------------- --------------------------------------
    Label                  Value
    ---------------------- --------------------------------------
    toBase32 (canonical)   01GHVYDVNW2S615RS2SA7HN27K
    toBase58               1BsMRvKcgozP4Kw2m4Fb1C
    toRfc4122              018477e6-eebc-164c-12e3-22ca8f1a88f3
    ---------------------- --------------------------------------
    Time                   2022-11-14 20:48:53.948 UTC
    ---------------------- --------------------------------------

    我不确定为什么原则不只存储 ULID,但它当前的行为并没有阻止您在项目中使用 ULID。 希望这有帮助!

    回复
    0
  • 取消回复