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 中存在的任何序列字段。
在找到更好的解决方案之前,这将保留为已接受的答案。
如何在非主键列上使用 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 中存在的任何序列字段。
在找到更好的解决方案之前,这将保留为已接受的答案。