Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HIbernate issue with Oracle Trigger for generating id from a sequence

We have a before insert trigger that gets the next value from sequence. When the object is persisted with save() method, hibernate gets the value from the sequence and adds it to the object. and when the transaction is committed from Spring's service layer, the ID value is again increased on the database. how do I avoid getting nextval() if the object already has an id..

Here is what I ma trying to do..

UserDao

public User saveUser(User user){
      session.getCurrentSession.save(user);//line2
      return user;//line3  
 }

UserService

public void saveUserAndWriteToAudit(User user, UserAudit userAudit){
  userDao.saveUser(user);//line1
  userAudit.setUserId(user.getId);//line4
  userAudit.saveUserAudit(userAudit);//line5
}

And the User Class

 @Entity
  public class User{

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO, generator="a1")
     @SequenceGenerator(name="a1", sequenceName="usersequence")
     private Long id;
     /////////////////
 }

When the cursor reaches line1 and line2 user object has null in id attribute. after line2, it has nextval from sequence - lets say 1. on line4, i have added user's id=1 to useraudit object.. when transaction is committed after line 5, 2 is inserted into User's id column and 1 into UserAudit's userId column. This serves no purpose to me :( How do I avoid this issue? Thanks!

like image 496
RKodakandla Avatar asked Nov 03 '11 21:11

RKodakandla


2 Answers

The above solution is great, it's saved me a lot of headaches on this problem.

My only gripe is it opens the door to user/codes to insert any ID value without actually inquiring the sequence.

I've found the following solution also works. It lets Hibernate find the max ID and have it incremented every time an insert statement is executed. But when it hits the database, the ID is ignored and replaced by the one generated by the trigger, so there's no uniqueness in a cluster problem:

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;

The biggest drawback is @GenericGenerator is a Hibernate annotation, so you lose JPA's portability. It's also not clear to the programmers that this ID is actually linked to a sequence while in fact, it's one of the tightest coupled solutions that use a sequence.

like image 56
Christopher Yang Avatar answered Nov 08 '22 09:11

Christopher Yang


Just update your trigger to only fire when not given an id.

create or replace
trigger sa.my_trigger
before insert on sa.my_table
for each row
when (new.id is null)
begin
   select sa.my_sequence.nextval
    into :new.id
    from dual;
end;
like image 30
Matthew Watson Avatar answered Nov 08 '22 08:11

Matthew Watson