Solved

hibernate saveOrUpdate

Posted on 2006-06-09
8
17,093 Views
Last Modified: 2013-11-24
I have a PROGRAM table.  It's keyed by program_id generated by an oracle sequence.  It also has a program_name field which is not null and unique.

Here's how it's mapped:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
      <class name="smefsModel.pojo.Program" table="PROGRAM" schema="SMEFS">
            <id name="programId" column="PROGRAM_ID" type="long">
                  <generator class="sequence">
                        <param name="sequence">SMEFS_SEQ</param>
                  </generator>
            </id>
            <natural-id mutable="true">
                  <property name="programName" type="string" column="PROGRAM_NAME" length="30" unique="true" not-null="true" />
            </natural-id>
            <property name="programDesc" type="string" column="PROGRAM_DESC" length="100" />
      </class>
</hibernate-mapping>

So here the question: is there a built-in way to make sure that when I try to saveOrUpdate a program and it has the same program_name, it would automatically know to just update the existing one and not to generate a new sequence-based program_id.

So, for example, currently, when I do:
1      Program program1 = new Program("yo");
2      session.saveOrUpdate(program1);
3      Program program2 = new Program("yo");
4      program2.setProgramDesc("whatup");
5      session.saveOrUpdate(program2);

For line 5, I get:    
insert
    into
        SMEFS.PROGRAM
        (PROGRAM_NAME, PROGRAM_DESC, PROGRAM_ID)
    values
        (?, ?, ?)
10:45:50,866 DEBUG StringType:79 - binding 'yo' to parameter: 1
10:45:50,866 DEBUG StringType:71 - binding null to parameter: 2
10:45:50,866 DEBUG LongType:79 - binding '301028540' to parameter: 3
10:45:50,882  WARN JDBCExceptionReporter:71 - SQL Error: 1, SQLState: 23000
10:45:50,882 ERROR JDBCExceptionReporter:72 - ORA-00001: unique constraint (SMEFS.PROGRAM_UX1) violated

because it tries to insert a new record (and then, of course, it bombs since program_name is unique), instead of updating the existing one.  This happens because the key to the table is the sequence-based program_id rather than program_name.


0
Comment
Question by:aturetsky
  • 4
  • 4
8 Comments
 
LVL 6

Expert Comment

by:phuocnh
Comment Utility
Hi aturetsky !
Please read here:
http://www.systemmobile.com/articles/IntroductionToHibernate.html#Creating%20and%20Updating%20Persistent%20Classes
Focus on the following lines:
"The saveOrUpdate(Object) call will save the object if the id property is null, issuing a SQL INSERT to the database. This refers to the unsaved-value attribute that we defined in the Player mapping document. If the id is not null, the saveOrUpdate(Object) call would issue an update, and a SQL UPDATE would be issued to the database. (Please refer to the sidebar Unsaved-Value Strategies for more information on this topic.)"
And here about "Unsaved Value Strategies"
The unsaved-value attribute supported by the id element indicates when an object is newly created and transient, versus an object already persisted. The default value is null, which should be sufficient for most cases. However, if your identifier property doesn't default to null, you should give the default value for a transient (newly created) object.Additional values supported by the unsaved-value attribute are: any, none and id-value.
Phuoc
0
 
LVL 1

Author Comment

by:aturetsky
Comment Utility
I don't think unsaved-value is applicable here, since at the point of saveOrUpdate my instance is certainly newly created and transient.  It's just that when that newly created instance has a program_id key that matches one already in the database, hibernate is smart enough to issue an update rather than insert.  For example if I have a record with program_id 123 already in the DB and then do:

Program program = new Program();
program.setProgramId(new Long(123));
program.setProgramName("blah");
session.saveOrUpdate(program);

hibernate is smart enough to realize that the record with that program_id is already in DB and to issue an update and not to insert a new record with a new sequence-based program_id

but if I have a record with program_name "blah" already in the DB and then do:

Program program = new Program();
program.setProgramName("blah");
program.setProgramDesc("ssup");
session.saveOrUpdate(program);

hibernate doesn't realize that a record with program_name "blah" is already sitting in the database and that all that needs to be done is an update on a program_desc, but rather attempts to issue an insert with a new sequence-based program_id, resulting in a unique constraint violation error on the program_name field

So I am not sure how unsaved-value would help me here.

0
 
LVL 6

Expert Comment

by:phuocnh
Comment Utility
Hi aturetsky!
Quote:
but if I have a record with program_name "blah" already in the DB and then do:

Program program = new Program();
program.setProgramName("blah");
program.setProgramDesc("ssup");
session.saveOrUpdate(program);

hibernate doesn't realize that a record with program_name "blah" is already sitting in the database and that all that needs to be done is an update on a program_desc, but rather attempts to issue an insert with a new sequence-based program_id, resulting in a unique constraint violation error on the program_name field
My idea:
The objects is distinguished between each others by object identifier.
In your example, the record in your db with program_name "blah" is associated object with object identifier x because programe_name is not an object identifier.
When you do the following task:
Program program = new Program();
program.setProgramName("blah");
program.setProgramDesc("ssup");
session.saveOrUpdate(program);
your program object has an identifier whose value is y.
x<>y so they are two different objects so hibernate must be use "insert" instead of update.
Your table with program_name is unique why don't you use it as identifier of the objects?
Phuoc

 
0
 
LVL 1

Author Comment

by:aturetsky
Comment Utility
Good DB design practices and hibernate authors recommend refraining from using a natural id as a key.  For one thing, despite its uniqueness, its value may be changed later on.  That's why I did not want to use program_name as key, and created a surrogate, sequential program_id key instead.

I realize it looks at the key to determine whether to insert or update.  I wish however, that using the natural-id element in hibernate mapping would not only tag it as unique and not null, but also have impact on the insert update behavior.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 6

Expert Comment

by:phuocnh
Comment Utility
Hi aturetsky!
I think you should use merg for the first time and saveOrUpdate for another time
For first time:
program1 = merge(program1);
The other times:
Program program = new Program();
program.setProgramId(program1.getProgramId());
program.setProgramName("blah");
program.setProgramDesc("ssup");
session.saveOrUpdate(program);
Phuoc
0
 
LVL 1

Author Comment

by:aturetsky
Comment Utility
well, in my case, that's the whole problem - the program doesn't know which time is first and which isn't until it looks to see if it's already in the database.  Now, of course, I can try to do a find by that program_name first and see if it's there - but that's exactly what I was trying to avoid.

Having said that, I am curious why you would recommend a merge rather than a find by program name.  What would be the goal of merge here?
0
 
LVL 6

Accepted Solution

by:
phuocnh earned 250 total points
Comment Utility
OK!
find is a solution but merge is simpler than find because of  giving the condition.
merge will look up in the db if the object is not found, it save the object into db and return the persistent object.
(note that in your case if the object aldready exists in the DB, merge also save into the DB and exception will occur because of their identifiers)
Phuoc
 
0
 
LVL 1

Author Comment

by:aturetsky
Comment Utility
note to the reader:
while the previous post is marked as accepted due to its general usefulness, please note that there does not appear to be a built-in way to drive insert-update behavior based on the value of non-key field, even if it's a candidate, natural key.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
count7 challenge 12 66
Non-recursive backtracking, using a stack 1 47
listing all functions in JavaScript 19 98
eclipse formatting 6 38
An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now