PetaPoco 插入在 PostgreSQL 中具有多个触发器的表上失败

PetaPoco insert fails on tables with multiple triggers in PostgreSQL

PetaPoco/Npgsql 使用 table 触发器插入失败。

我认为这与 PetaPoco insert fails on table with trigger 非常相似,不同之处在于该问题针对的是 SQL 2008 而我的问题针对的是 PostgreSQL 9.5.4 使用带有 table 的 Npgsql C# 驱动程序 多个 触发器。 我的情况是 tables 在 PostgreSQL 中定义了多个触发器,例如:

CREATE TABLE procedures
(
  recid serial NOT NULL,
  orderno integer NOT NULL,
  torder timestamp without time zone NOT NULL DEFAULT now(),
  cpt_recid integer NOT NULL,
  dx_recid integer,
  send_out boolean,
  modified timestamp without time zone NOT NULL DEFAULT now(),
)
WITH (
  OIDS=FALSE
);
ALTER TABLE procedures
  OWNER TO postgres;


CREATE TRIGGER update_modified
  BEFORE UPDATE
  ON procedures
  FOR EACH ROW
  EXECUTE PROCEDURE update_modified();

CREATE TRIGGER zzz_get_next_order_number_trigger
  BEFORE INSERT
  ON procedures
  FOR EACH ROW
  EXECUTE PROCEDURE getnextorderno();


CREATE OR REPLACE FUNCTION getnextorderno()
  RETURNS trigger AS
$BODY$

BEGIN
    NEW.orderno := nextval('order_number_seq');
    Return NEW; 
END;

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION getnextorderno()
  OWNER TO postgres;

我的主要问题是 PetaPoco database.Insert() 坚持保存 0 和纪元时间而不是下一个订单号或当前时间。

是否可以对 PetaPoco 进行简单的更改以遵守列上的默认值或允许触发器正常运行?

(我对 PetaPoco 很陌生)。

TIA

编辑#1 按照提议的更改,table 现在看起来如下所示。我仍然遇到的问题是 orderno 仍然被 0 填充,因此违反了唯一约束。

duplicate key value violates unique constraint "procedure_order_unique" Key (orderno)=(0) already exists.

PetaPoco 插入从 WCF 服务调用为:

p = new procedure
                    {
                        cpt_recid = cpt.recid,
                        chart_recid = _procedure.chart_recid,
                        dx_recid = _procedure.dx_recid,
                        torder = _procedure.torder,
                        on_return_to_office = _procedure.on_return_to_office,
                        send_out = _procedure.send_out,
                        standing_order = _procedure.standing_order,
                        stat = _procedure.stat,
                        tstop = _procedure.tstop,
                        isprocedure = _is_procedure
                    };
                    db.Insert(p);

CREATE TABLE procedures
(
  recid serial NOT NULL,
  orderno integer NOT NULL DEFAULT nextval('order_number_seq'::regclass),
  torder timestamp without time zone NOT NULL DEFAULT now(),
  cpt_recid integer NOT NULL,
  dx_recid integer,
  send_out boolean,
  modified timestamp without time zone NOT NULL DEFAULT now(),
  stat boolean,
  standing_order boolean,
  tstop timestamp without time zone,
  on_return_to_office boolean,
  chart_recid integer NOT NULL,
  isprocedure boolean NOT NULL DEFAULT false,
  is_deferred boolean,
  CONSTRAINT procedures_pk PRIMARY KEY (recid),
  CONSTRAINT procedures_chart_fk FOREIGN KEY (chart_recid)
      REFERENCES charts (recid) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT procedures_cpt_fk FOREIGN KEY (cpt_recid)
      REFERENCES cpt (recid) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT procedures_dx_fk FOREIGN KEY (dx_recid)
      REFERENCES dx (recid) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE RESTRICT,
  CONSTRAINT procedure_order_unique UNIQUE (orderno)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE procedures
  OWNER TO postgres;

CREATE TRIGGER insert_modified
  BEFORE INSERT
  ON procedures
  FOR EACH ROW
  EXECUTE PROCEDURE update_modified();

CREATE TRIGGER update_modified
  BEFORE UPDATE
  ON procedures
  FOR EACH ROW
  EXECUTE PROCEDURE update_modified();

感谢您的帮助。

您不需要订单号的触发器,只需在列上设置顺序并删除触发器的需要。

正在保存修改,因为您修改的 POCO 属性 不为空,因此它正在发送默认值。如果你想防止这种情况发生,请在插入前/更新前对两者进行修改后的触发器 运行。

BEFORE INSERT OR UPDATE

http://www.toptensoftware.com/petapoco/

文档说用主键修饰 class 定义:

[PetaPoco.PrimaryKey("orderno")]

要避免使用属性装饰 table 和修改 T4 模板,您需要将列命名为 id

PetaPoco 将在插入时忽略它并允许数据库处理它。

任何其他列名都将被假定为非主键,并且将发送默认值。

PostgreSQL 和 SQL 服务器都将忽略 SERIALIDENTITY 列,当在插入时给出值就像您的场景中发生的那样。

在 Phill 的带领下(上图)并且不想更改 PostgreSQL 过程 table 本身,我发现以下工作正常:

  1. "Tweak" PetaPoco Database.tt T4 模板具有:

    tables["procedures"]["orderno"].PropertyType="int?";        // Setting default value of orderno to null forces PostgreSQL trigger.
    
  2. 将触发程序更改为:

    CREATE OR REPLACE FUNCTION getnextorderno()
        RETURNS trigger AS
     $BODY$
    
    BEGIN
    IF NEW.orderno is null THEN
        NEW.orderno := nextval('order_number_seq');
    END IF; 
    
    Return NEW; 
    END;
    
    $BODY$
     LANGUAGE plpgsql VOLATILE
    COST 100;
    ALTER FUNCTION getnextorderno()
    OWNER TO postgres;
    

根据上面的 Phill,如果使用值 0,触发器将被忽略。