【问题标题】:Doctrine 2 and Postgres, serial field on non primary key columnsDoctrine 2 和 Postgres,非主键列上的串行字段
【发布时间】:2020-06-04 00:37:21
【问题描述】:

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

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

我有这样的表:

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"'

我想要的是,当我在这个表中插入新行时,我不必明确指定顺序,但 db 应该处理它。

原则上生成的 sql 代码应如下所示:

insert into test (DEFAULT, DEFAULT);

在没有任何配置的情况下,学说尝试在“order”列中插入null,导致错误“can't insert null value into not null field”

我尝试了什么

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

private $order = 'DEFAULT'

但这错误地显示为“整数的无效语法”

然后我尝试将选项放入 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 中,有一个 Zend_Db_Exp 类,当在 sql 语句中使用时,它没有被引用,并且值按原样使用。我想我在这里需要类似的东西。

版本信息

PHP 7.3

Postgres 11

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

【问题讨论】:

    标签: php postgresql doctrine-orm


    【解决方案1】:

    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;
    

    并将其附加到表格:

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

    这是一个仅针对订单字段的临时触发器,它可能适用于处理目标表中存在的任何串行字段。


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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      • 2017-07-08
      相关资源
      最近更新 更多