插入触发器导致EntityNotFoundException

时间:2014-12-22 23:48:26

标签: java postgresql triggers entity persistence

我可以使用一些帮助来解决这个问题。我浪费了一天寻找答案而没有找到任何东西。

我有一个Entity和Model类。实体是简化数据,模型是实体的控制器。在数据库上,我有一个触发器,当AFTER INSERT发生时,弹出触发器来更新另一个表的信息。发生的事情是,在EntityManager的持久化和刷新之后,调用刷新并导致“EntityNotFoundException”。如果我拿出触发器上的插入物,那么一切都是笨拙的。这是下面的代码:

让球滚动的方法

    public FTL createPaymentByAccountNumberLoanNumber(String accountNumber, Integer loanNumber, Payment payment) {

        EntityManager em = getEntityManager();

        Loan loan = checkLastLoan(accountNumber, loanNumber);

        BigDecimal totalAmount =
                payment.getAppliedToBalance()
                .add(payment.getAppliedToXXX())
                .add(payment.getAppliedToYYY())
                .add(payment.getAppliedToZZZ());

        FT ft = new FT ();            
        ft.setTransactionAmount(totalAmount);
        em.persist(ft);

        FTL lastFtl = FTL.loadLastByLoan(loan);
        em.detach(lastFtl);

        FTL ftl = new FTL(ft);
        ftl.setTransactionAmount(totalAmount);
        ftl.setAppliedToBalance(payment.getAppliedToBalance());
        ftl.setAppliedToXXX(payment.getAppliedToLateCharge());
        ftl.setAppliedToYYY(payment.getAppliedToMaturityInterest());
        ftl.setAppliedToZZZ(payment.getAppliedToNsfCharge());
        ftl.setTransactionCode(TransactionCode.Collection);
        ftl.setNewEndingBalance(lastFtl.getNewEndingBalance().subtract(payment.getAppliedToBalance()));
        ftl.setLoan(loan);

        em.persist(ftl);
        em.flush();         
        em.refresh(ft);
        em.refresh(ftl); //THIS IS WHERE THE EXCEPTION OCCURES WHEN GOING THROUGH DEBUG
        em.detach(ftl);

        evict(Loan.class, loan.getLoanId());

        return ftl;
    }

FTL_loan_movement_trigger

    CREATE TRIGGER FTL_loan_movement_trigger
    AFTER INSERT
    ON FTL
    FOR EACH ROW
    EXECUTE PROCEDURE loan_movement_trigger();

loan_movement_trigger

    CREATE OR REPLACE FUNCTION loan_movement_trigger()
      RETURNS trigger AS
    $BODY$
    DECLARE
        _loan_id bigint;
        _loan_movement_status integer;
        _loan_current_status integer;
        _ending_balance numeric;
    BEGIN
      _loan_id := NEW.loan_id;

      RAISE NOTICE 'Finding the statuses of the loan: %', _loan_id;

      --Find the currently saved off status of the loan
      _loan_movement_status := (SELECT fls.status FROM find_loan_status(_loan_id, now()::date) fls);
      --Calculate the current status of the loan
      _loan_current_status  := (SELECT * FROM calc_loan_current_status(_loan_id) clcs);

      RAISE NOTICE 'Movement % and Current %', _loan_movement_status, _loan_current_status;

      IF(_loan_movement_status != _loan_current_status) THEN
         _ending_balance := (SELECT * FROM calc_ending_balance(_loan_id, now()::date));

         RAISE NOTICE 'New ending balance: %', _ending_balance;
    --/*  THIS INSERT RIGHT HERE IS WHAT IS CAUSING THE EXCEPTION!!!!!!!
         INSERT INTO loan_movement
        (movement_date,
            loan_id,
            status,
            remaining_balance,  
            created_by,
            organization_id) 
        VALUES
        (now(), 
            9999999, 
            _loan_current_status, 
            _ending_balance,
            1,
            1);

         RAISE NOTICE 'Inserted into loan_movement';
     --*/

      END IF;
      RETURN NEW;

    END;

1 个答案:

答案 0 :(得分:1)

PL / pgSQL应该是(多个)SQL语句的服务器端执行的粘合剂。不要像使用Java这样的过程语言那样使用子函数和赋值来模块化你的代码,效率非常低。尝试使用一些可以同时执行大量工作的SQL语句。围绕它构建你的plpgsql代码。

使用 SQL语句可以大大简化您的触发器功能:

CREATE OR REPLACE FUNCTION loan_movement_trigger()
  RETURNS trigger AS
$func$
BEGIN
   WITH loan AS (SELECT calc_loan_current_status(NEW.loan_id) AS _current)
   INSERT INTO loan_movement (movement_date, loan_id, status
             , remaining_balance, created_by, organization_id) 
   SELECT now(), 9999999, l._current
        , calc_ending_balance(NEW.loan_id, now()::date), 1, 1
   FROM   loan l
   WHERE  l._current IS DISTINCT FROM
         (find_loan_status(NEW.loan_id, now()::date)).status;

   RETURN NULL;  -- can just be NULL for AFTER trigger
END
$func$ LANGUAGE plpgsql;

您的IF表达式可能有误,因为它不适用于NULL值。

IF(_loan_movement_status != _loan_current_status) THEN

如果两个值都为非NULL且不同,则仅计算为TRUE。我用IS DISTINCT FROM重写了以覆盖NULL值 另外,我将整个IF构造替换为WHERE的{​​{1}}条件,以及基本上所有其他内容。