在 npgsql 中准备语句和批处理

Mik*_*kim 5 npgsql

Simple Preparation文档中的示例(https://www.npgsql.org/doc/prepare.html#simple-preparation 显示了在准备命令后设置参数的示例。

var cmd = new NpgsqlCommand(...);
cmd.Parameters.Add("param", NpgsqlDbType.Integer);
cmd.Prepare();
// Set parameters
cmd.ExecuteNonQuery();
// And so on
Run Code Online (Sandbox Code Playgroud)

问题

  1. 参数如何设置?
  2. 是否可以使用AddWithValue而不是使用指定的方法Add-文档说“不支持设置值”?AddWithValue(String, NpgsqlDbType, Object)NpgsqlDbType
  3. 如果同一命令中存在多个语句,这将如何工作?

这个答案(/sf/answers/3728766331/)表明可以一起准备单个字符串中的多个命令,但不清楚如何创建此 CommandText 字符串。


编辑:我想我已经快到了,但我不确定如何创建和执行批量查询字符串。这是我使用 StringBuilder 构建批量查询的天真尝试。这是行不通的。我该如何正确地做到这一点?

using System;
using System.Collections.Generic;
using System.Text;
using Npgsql;
using NpgsqlTypes;

class Model
{
    public int value1 { get; }
    public int value2 { get; }

    public Model(int value1, int value2)
    {
        this.value1 = value1;
        this.value2 = value2;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var dataRows = new List<Model>();
        dataRows.Add(new Model(3,2));
        dataRows.Add(new Model(27,-10));
        dataRows.Add(new Model(11,-11));

        var connString = "Host=127.0.0.1;Port=5432;Username=postgres;Database=dbtest1";

        // tabletest1
        // ----------
        //   id        SERIAL PRIMARY KEY
        // , value1    INT NOT NULL
        // , value2    INT NOT NULL

        using (var conn = new NpgsqlConnection(connString))
        {
            conn.Open();

            var cmd = new NpgsqlCommand();
            cmd.Connection = conn;
            cmd.CommandText = $"INSERT INTO tabletest1 (value1,value2) VALUES (@value1,@value2)";
            var parameterValue1 = cmd.Parameters.Add("value1", NpgsqlDbType.Integer);
            var parameterValue2 = cmd.Parameters.Add("value2", NpgsqlDbType.Integer);
            cmd.Prepare();

            var batchCommand = new StringBuilder();

            foreach (var d in dataRows)
            {
                parameterValue1.Value = d.value1;
                parameterValue2.Value = d.value2;
                batchCommand.Append(cmd.CommandText);
                batchCommand.Append(";");
            }
            Console.WriteLine(batchCommand.ToString());
            // conn.ExecuteNonQuery(batchCommand.ToString());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Sha*_*sky 7

1) 只需捕获从返回的 NpgsqlParameter Add(),然后设置其 Value 属性:

var p = cmd.Parameters.Add("p", NpgsqlDbType.Integer);
cmd.Prepare();
p.Value = 8;
cmd.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)

2) 您可以AddWithValue()以相同的方式使用,但如果您准备命令是为了多次重复使用它,那就没有什么意义了。这个想法是,首先添加不带值的参数,然后准备,然后执行几次,每次都设置值。

3) 您可以准备多语句命令。现在,命令中的所有语句都将共享相同的参数列表(位于 NpgsqlCommand 上)。因此,同样的模式成立:使用 SQL 和参数创建命令,准备它,然后设置参数值并执行。命令中的每个单独语句都将准备好运行,从而受益于性能的提高。

这是两个语句批处理的示例:

cmd.CommandText = "INSERT INTO tabletest1 (value1,value2) VALUES (@v1,@v2); INSERT INTO tabletest1 (value1, value2) VALUES (@v3,@v4)";
var v1 = cmd.Parameters.Add("v1", NpgsqlDbType.Integer);
var v2 = cmd.Parameters.Add("v2", NpgsqlDbType.Integer);
var v3 = cmd.Parameters.Add("v3", NpgsqlDbType.Integer);
var v4 = cmd.Parameters.Add("v4", NpgsqlDbType.Integer);
cmd.Prepare();

while (...) {
    v1.Value = ...;
    v2.Value = ...;
    v3.Value = ...;
    v4.Value = ...;
    cmd.ExecuteNonQuery();
}
Run Code Online (Sandbox Code Playgroud)

但是,如果目标是有效插入大量数据,请考虑使用 COPY - 它甚至比批量插入更快。

最后,为了完成图片,特别是对于 INSERT 语句,您可以在单个语句中包含多行:

INSERT INTO tabletest1 (value1, value2) VALUES (1,2), (3,4)
Run Code Online (Sandbox Code Playgroud)

您还可以再次参数化实际值,并准备此命令。这类似于批处理两个 INSERT 语句,并且应该更快(尽管仍然比 COPY 慢)。