Doctrine 2 和 Postgres,非主键列上的序列字段

Doctrine 2 and Postgres, serial field on non primary key columns

如何在非主键列上使用 Doctrine 2 中的串行数据类型?

Doctrine 可以使用序列列作为主键,生成器策略 设置为 SEQUENCE 或 IDENTITY,但生成器不能用于非主键列。

我有 table 这样的:

create table test (
    id integer not null generated by default as identity, 
    order serial
)
constraint test_pk primary key (id)

学说实体:

App\Entity\Test:
    type: entity
    table: test

    id:
        id:
            type: integer
            nullable: false
            id: true
            generator:
                strategy: SEQUENCE
            sequenceGenerator:
                sequenceName: test_id_seq
    fields:
        order:
            type: integer
            nullable: false
            column: '"order"'

我想要的是,当我向 table 中插入新行时,我不必明确指定顺序,但数据库应该会处理它。

原则上 sql 代码应该如下所示:

insert into test (DEFAULT, DEFAULT);

在没有任何配置的情况下,doctrine 尝试将 null 插入列 "order" 导致错误 "can't insert null value into not null field"

我试过的

我尝试在 php 实体 class 中为 "order" 属性 设置默认值,如下所示:

private $order = 'DEFAULT'

但错误的是 "invalid syntax for integer"

然后我尝试像这样将选项放入 yaml 定义中:

fields:
        order:
            type: integer
            nullable: false
            column: '"order"'
            options:
                default: DEFAULT

这没有任何区别。

然后我尝试创建名为 order 的自定义类型,但也失败了。

自定义类型代码:

use Doctrine\DBAL\Types\Type;

class OrderType extends Type
{
    public function getName(): string
    {
        return 'order';
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (is_numeric($value)) {
            return $value;
        }

        return 'DEFAULT';
    }

    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
    {
        return 'DEFAULT';
    }

    public function canRequireSQLConversion(): bool
    {
        return true;
    }

    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        return 'serial';
    }
}

这以错误 "SQLSTATE[HY093]: Invalid parameter number: parameter was not defined" 结束,这是方法 convertToDatabaseValueSQL 的问题。当我将其注释掉并使用默认实现时,出现错误 "SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "DEFAULT""

它仍然引用单词 DEFAULT 但我需要它不被引用,它必须用作关键字而不是字符串。

我认为自定义类型应该可以正常工作。在旧的 Zend Framework v1 中有 class Zend_Db_Exp ,当在 sql 语句中使用时,它没有被引用并且值按原样使用。我想我需要类似的东西。

版本信息

PHP 7.3

Postgres 11

Doctrine ORM 2.6(如果需要我会升级)

DB 触发器可用于管理行为不当的客户端,在本例中是基于 Doctrine 2 的应用程序。

创建触发器函数:

create or replace function public."t_setDefaultValueOnOrderField"()
    returns trigger as
$body$
declare
    fq_table_name text := '"' || TG_TABLE_SCHEMA || '"' || '.' || '"' || TG_TABLE_NAME || '"';
    sequence_name text := pg_get_serial_sequence(fq_table_name, 'order');
begin
    if NEW.order is null then
        NEW.order := nextval(sequence_name);
    end if;

    return NEW;
end;
$body$ language plpgsql;

并将其附加到 table:

create trigger "setDefaultValueOnOrderField"
    before insert
    on public.test
    for each row
execute procedure public."t_setDefaultValueOnOrderField"();

这只是订单字段的临时触发器,它可能适用于处理目标 table 中存在的任何序列字段。


在找到更好的解决方案之前,这将保留为已接受的答案。