You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让LinqToDB生成含OVERRIDING SYSTEM VALUE的PostgreSQL插入语句?

解决LinqToDB插入PostgreSQL自增ID(GENERATED ALWAYS)的问题

问题场景

PostgreSQL中存在表tbl,结构如下:

CREATE TABLE "tbl"
(
    "id" bigint generated always as identity
        constraint pk_key primary key
);

手动插入指定ID值时,需要在SQL中添加OVERRIDING SYSTEM VALUE:

INSERT INTO contracts.loan_contracts1 (id)
OVERRIDING SYSTEM VALUE -- 允许手动插入ID值
VALUES (10);

对应的LinqToDB实体定义:

[Table("tbl", Schema = "public")]
public class TblEntity : IIdentifiable<long>
{
    [Column("id")]
    [PrimaryKey]
    [Identity]
    public long Id { get; set; }
}

使用connection.InsertWithId(new TblEntity(){Id = 10});执行插入时触发报错:

MessageText: cannot insert into column "id"
Detail: Column "id" is an identity column defined as GENERATED ALWAYS.
Hint: Use OVERRIDING SYSTEM VALUE to override.

需求明确:

  • 保留实体的[Identity]特性
  • 使用LinqToDB生成插入语句
  • 不使用LinqToDB特定的Value链式语法

解决方案

方案一:自定义PostgreSQL自动追加子句

通过扩展LinqToDB的PostgreSQL方言,让框架自动识别插入操作中是否包含显式赋值的Identity字段,自动添加OVERRIDING SYSTEM VALUE。

  1. 创建自定义方言类
public class CustomPostgreSQLDialect : PostgreSQLDialect
{
    public override void BuildInsertClause(QueryBuilder builder, InsertStatement insert)
    {
        base.BuildInsertClause(builder, insert);
        
        // 检查是否有Identity字段被显式赋值
        var hasExplicitIdentity = insert.Columns
            .Any(col => 
                col.Expression is ColumnExpression ce 
                && ce.Column.IsIdentity 
                && col.Expression != null);
        
        if (hasExplicitIdentity)
        {
            builder.AppendLine().Append("OVERRIDING SYSTEM VALUE");
        }
    }
}
  1. 注册自定义方言
    可以全局注册方言,或在创建连接时指定:
// 全局注册(应用启动时执行)
DataConnection.AddMappingSchema(new MappingSchema(new CustomPostgreSQLDialect()));

// 或单个连接指定
using var connection = new DataConnection(
    ProviderName.PostgreSQL, 
    "your_connection_string", 
    new CustomPostgreSQLDialect());
  1. 执行插入
    现在使用InsertWithId插入带显式ID的实体时,LinqToDB会自动生成包含OVERRIDING SYSTEM VALUE的SQL:
var entity = new TblEntity { Id = 10 };
var insertedId = connection.InsertWithId(entity);

生成的SQL示例:

INSERT INTO public.tbl (id)
VALUES (@p0)
OVERRIDING SYSTEM VALUE
RETURNING id;

方案二:按需指定插入选项(更灵活)

如果需要按需控制是否添加OVERRIDING SYSTEM VALUE,可以通过扩展InsertOptions实现:

  1. 扩展InsertOptions
public static class InsertOptionsExtensions
{
    public static InsertOptions WithPostgreSqlOverridingSystemValue(this InsertOptions options)
    {
        options.SetExtension("PostgreSqlOverridingSystemValue", true);
        return options;
    }
}
  1. 修改自定义方言
    在方言中检查扩展参数:
public class CustomPostgreSQLDialect : PostgreSQLDialect
{
    public override void BuildInsertClause(QueryBuilder builder, InsertStatement insert)
    {
        base.BuildInsertClause(builder, insert);
        
        if (insert.Options?.GetExtension<bool?>("PostgreSqlOverridingSystemValue") == true)
        {
            builder.AppendLine().Append("OVERRIDING SYSTEM VALUE");
        }
    }
}
  1. 执行插入时指定选项
var entity = new TblEntity { Id = 10 };
connection.Insert(entity, options => options.WithPostgreSqlOverridingSystemValue());

内容的提问来源于stack exchange,提问作者VladimirK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:55:42