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

能否从.NET Core API向PostgreSQL函数传递表/列表/JSON并实现批量插入?

PostgreSQL批量插入发票明细:从.NET Core API传递批量参数到函数

PostgreSQL完全支持通过函数接收批量参数实现批量插入,针对你的发票明细场景,推荐以下三种方案:

方案1:使用自定义表类型作为函数参数

先创建与发票明细结构匹配的自定义表类型,再编写接收该类型数组的函数,实现批量插入,这是最贴合你示例思路的方案。

SQL代码

-- 1. 创建对应发票明细的自定义表类型
CREATE TYPE invoice_detail AS (
    line_item_no INT,
    product_id INT,
    quantity NUMERIC,
    unit_price NUMERIC,
    amount NUMERIC
);

-- 2. 创建批量插入函数
CREATE OR REPLACE FUNCTION insert_invoice_details(p_invoice_id BIGINT, p_details invoice_detail[])
RETURNS TABLE(detail_id BIGINT) AS $$
BEGIN
    RETURN QUERY
    INSERT INTO invoice_details (invoice_id, line_item_no, product_id, quantity, unit_price, amount)
    SELECT p_invoice_id, d.line_item_no, d.product_id, d.quantity, d.unit_price, d.amount
    FROM UNNEST(p_details) d
    RETURNING detail_id;
END;
$$ LANGUAGE plpgsql;

.NET Core调用代码(基于Npgsql)

// 定义明细实体类
public class InvoiceDetail
{
    public int LineItemNo { get; set; }
    public int ProductId { get; set; }
    public decimal Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal Amount { get; set; }
}

// 批量插入逻辑
using var conn = new NpgsqlConnection("你的数据库连接字符串");
await conn.OpenAsync();

var invoiceId = 123; // 已保存的发票ID
var details = new List<InvoiceDetail>
{
    new() { LineItemNo = 1, ProductId = 456, Quantity = 2, UnitPrice = 100, Amount = 200 },
    new() { LineItemNo = 2, ProductId = 789, Quantity = 1, UnitPrice = 50, Amount = 50 }
};

// 将明细转换为PostgreSQL自定义类型数组
var npgsqlDetails = details.Select(d => new NpgsqlCompositeRecord(
    new[] { NpgsqlDbType.Integer, NpgsqlDbType.Integer, NpgsqlDbType.Numeric, NpgsqlDbType.Numeric, NpgsqlDbType.Numeric },
    new object[] { d.LineItemNo, d.ProductId, d.Quantity, d.UnitPrice, d.Amount }
)).ToArray();

using var cmd = new NpgsqlCommand("SELECT * FROM insert_invoice_details(@invoiceId, @details)", conn);
cmd.Parameters.AddWithValue("invoiceId", invoiceId);
cmd.Parameters.AddWithValue("details", npgsqlDetails);
cmd.Parameters[1].NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Composite;
cmd.Parameters[1].TypeName = "invoice_detail";

// 获取插入后的明细ID
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
    var detailId = reader.GetInt64(0);
    // 处理返回的明细ID
}

方案2:传递JSON/JSONB参数

如果不想创建自定义类型,可以将明细序列化为JSON字符串传递给函数,在函数内解析后批量插入,灵活性更高。

SQL函数代码

CREATE OR REPLACE FUNCTION insert_invoice_details_json(p_invoice_id BIGINT, p_details JSONB)
RETURNS TABLE(detail_id BIGINT) AS $$
BEGIN
    RETURN QUERY
    INSERT INTO invoice_details (invoice_id, line_item_no, product_id, quantity, unit_price, amount)
    SELECT 
        p_invoice_id,
        (d->>'line_item_no')::INT,
        (d->>'product_id')::INT,
        (d->>'quantity')::NUMERIC,
        (d->>'unit_price')::NUMERIC,
        (d->>'amount')::NUMERIC
    FROM jsonb_array_elements(p_details) d
    RETURNING detail_id;
END;
$$ LANGUAGE plpgsql;

.NET Core调用代码

using var conn = new NpgsqlConnection("你的数据库连接字符串");
await conn.OpenAsync();

var invoiceId = 123;
var details = new List<InvoiceDetail> { /* 填充明细数据 */ };
var jsonDetails = JsonSerializer.Serialize(details);

using var cmd = new NpgsqlCommand("SELECT * FROM insert_invoice_details_json(@invoiceId, @details)", conn);
cmd.Parameters.AddWithValue("invoiceId", invoiceId);
cmd.Parameters.AddWithValue("details", jsonDetails, NpgsqlDbType.Jsonb);

using var reader = await cmd.ExecuteReaderAsync();
// 处理返回结果

方案3:直接使用批量复制(无需函数)

如果不需要封装成函数,Npgsql提供的BeginBinaryImport是效率最高的批量插入方式,适合大规模明细数据的场景。

.NET Core代码

using var conn = new NpgsqlConnection("你的数据库连接字符串");
await conn.OpenAsync();

var invoiceId = 123;
var details = new List<InvoiceDetail> { /* 填充明细数据 */ };

// 启动批量复制
using var writer = conn.BeginBinaryImport(
    "COPY invoice_details (invoice_id, line_item_no, product_id, quantity, unit_price, amount) FROM STDIN BINARY");

foreach (var detail in details)
{
    writer.StartRow();
    writer.Write(invoiceId);
    writer.Write(detail.LineItemNo);
    writer.Write(detail.ProductId);
    writer.Write(detail.Quantity);
    writer.Write(detail.UnitPrice);
    writer.Write(detail.Amount);
}

writer.Complete();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:35:12