【问题标题】:Data commit fails for "Upsert" / Merge function when calling through Npgsql通过 Npgsql 调用时“Upsert”/Merge 函数的数据提交失败
【发布时间】:2015-11-11 13:49:48
【问题描述】:

我正在使用 Npgsql 3.0.3 和 Postgres 9.4。这是我在 Postgres 中的代码:

CREATE TABLE temp_test
(
  id serial NOT NULL,
  name text,
  CONSTRAINT temp_test_pk PRIMARY KEY (id)
)

以及“Upsert”/merge 函数将更改的记录作为 refcursor 返回:

CREATE OR REPLACE FUNCTION test_save(
    v_ref refcursor,
    iv_id integer,
    v_name character varying)
  RETURNS refcursor AS
$BODY$ 
DECLARE
  v_ref alias for $1;
  v_id integer := iv_id;
BEGIN

  UPDATE onepm.temp_test
  SET name   = v_name
  WHERE id         = v_id;
  IF NOT FOUND THEN
  INSERT INTO onepm.temp_test
      (name)
  VALUES
      (v_name)
  RETURNING id INTO v_id;
  END IF;

  OPEN v_ref FOR
  SELECT id 
       , name
  FROM onepm.temp_test
  WHERE id = v_id;

  RETURN v_ref;
END;

$BODY$
  LANGUAGE plpgsql;

在我的 .net 项目中,我有以下返回 IDatareader 的函数:

public static IDataReader ExecuteReader()
        {
            NpgsqlConnection conn = new NpgsqlConnection(connectionString);
            conn.Open();

            NpgsqlTransaction _tran = conn.BeginTransaction();

            NpgsqlCommand cmd = conn.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = "SELECT onepm.test_save(@ref, @id, @name)";

            NpgsqlParameter _p = new NpgsqlParameter();
            _p.ParameterName = "@ref";
            _p.NpgsqlDbType = NpgsqlDbType.Refcursor;
            _p.NpgsqlValue = "ref";
            _p.Direction = ParameterDirection.InputOutput;
            cmd.Parameters.Add(_p);

            cmd.Parameters.Add(new NpgsqlParameter("@id", 1));
            cmd.Parameters.Add(new NpgsqlParameter("@name", "test"));

            cmd.ExecuteNonQuery();
            cmd.CommandText = "fetch all in \"ref\"";
            cmd.CommandType = CommandType.Text;

            return cmd.ExecuteReader();
        }

这一切都很好,我确实在阅读器中收到了插入或更新的记录,除了数据从未提交到表中 - 在 pgAdmin 中找不到数据。如果我在 pgAdmin 中调用相同的函数,一切正常 - 记录已提交:

SELECT onepm.test_save('v_ref', 1, 'xxxxxx');

FETCH ALL IN "v_ref";

感谢您的帮助!

【问题讨论】:

    标签: c# .net postgresql transactions npgsql


    【解决方案1】:

    嗯,我认为你需要提交你开始的事务......!

    无论如何,您可能还想看看 PostgreSQL 9.5 的新内置 upsert 功能...

    【讨论】:

    • 感谢您的回答!问题是,如果我提交事务,我将失去获取数据的能力。有没有办法定义 refcursor “WITH HOLD”?
    • 好吧,你的函数没有真正的理由返回一个引用 - 你可以修改它来返回一个简单的表(见postgresql.org/docs/current/static/sql-createfunction.html)。然后,您可以在单个 SQL 调用中调用您的函数 (SELECT * FROM onepm.test_save(...)),并且可以完全删除 BeginTransaction()...
    • 谢谢,这可以解决必须定义返回表的痛苦。我们需要在插入时由 db 计算的值的新记录... Npgsql 会使用新的 upsert 语句以不同的方式处理这个问题吗?
    • 你也可以返回一条记录(见stackoverflow.com/a/6085167/640325)。 PG 9.5 upsert 功能在此处记录:wiki.postgresql.org/wiki/…。 Npgsql 不知道也不关心它,它只是提供它。不确定它是否适合您尝试做的事情,
    • 返回记录也是半令人满意的,因为我们必须再次将记录类型修改为类似的列。我回到最初的问题:从 Npgsql 中的游标中获取数据后,有没有办法控制提交?直接拨打电话时似乎效果很好。无论如何,谢谢!
    猜你喜欢
    • 2019-08-30
    • 2013-09-27
    • 1970-01-01
    • 2020-01-07
    • 2021-08-21
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多