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

时间:2016-09-07 05:54:14

标签: postgresql npgsql petapoco

PetaPoco / Npgsql在使用表触发器插入时失败。

我认为这与PetaPoco insert fails on table with trigger非常相似,不同之处在于问题是针对SQL 2008而我的是 PostgreSQL 9.5.4 使用Npgsql C#驱动程序,其中包含一个表多个 触发器。我的情况是我在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和纪元时间而不是下一个orderno或当前时间。

是否可以对PetaPoco进行简单的更改,以尊重列上的DEFAULTS或允许触发器正常运行?

(我对PetaPoco很新)。

TIA

编辑#1根据建议的更改,该表现在如下所示。我仍然遇到的问题是 orderno仍然被0 填充,因此违反了唯一约束。

  

重复键值违反了唯一约束   “procedure_order_unique”键(orderno)=(0)已经存在。

正在从WCF服务调用PetaPoco插入:

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();

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

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

正在保存修改,因为您的POCO修改属性不为null,因此它发送默认值。如果你想防止这种情况,你的修改后的触发器会在插入/更新之前同时运行。

BEFORE INSERT OR UPDATE

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

文档说要使用主键修饰类定义:

[PetaPoco.PrimaryKey("orderno")]

要使用属性修改表格并修改T4模板,您需要为列id命名。

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

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

PostgreSQL和SQL Server将在插入时给出值,忽略SERIALIDENTITY列,就像场景中发生的那样。

答案 1 :(得分:0)

以Phill为主导(上图)并且不想更改PostgreSQL过程表本身,我发现以下内容正常:

  1. “调整”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;
    
  3. 根据上面的Phill,如果使用值0,则将忽略触发器。