These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: one-to-many relashionship + cascade
PostPosted: Tue May 11, 2004 1:00 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
Has anyone worked with one-to-many relationships with "cascade" ? It works fine without cascade. However, with cascading, it fails to save new children (issuing sql "update" instead of "insert"). I've made it bi-directional as recommended, but no use.
I'd greatly appreciate it if anyone could spare the time to have a look. Thanx a lot in advance.

Code:

The relationship:  Department has several Employees.
------------------------
The classes:
------------------------
public class Employee {
   String id;
   double salary;
   Department  dept;
   // Constructors
   // Setters, getters , equals, hashCode
}
public class Department {
   String id;
   Set employees;
   // Constructors
   // setters, getters, equals, hashCode
   
   public void addEmployee(Employee e){
       employees.add(e);
       e.setDept(this);     // bi-directional
   }
}
------------------------
Mapping (bi-di relashionship, with "inverse=tue" and "cascade="all":
------------------------
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-2.0.dtd">

<hibernate-mapping package="test">
    <class name="Employee" table="Employee">
        <id name="id" column="id" type="string" >
            <generator class="assigned"/>
        </id>
       <property name="salary" />
       <many-to-one name="dept" class="Department" column="dept_id"  />
   </class>   
   <class name="Department" table="Dept">
       <id name="id" column="id" type="string" >
            <generator class="assigned"/>
       </id>
       <set name="employees" inverse="true" cascade="all">
             <key column="dept_id"/>
             <one-to-many class="Employee" />
       </set>      
    </class>
</hibernate-mapping>

------------------------
Usage:
------------------------
public static void main(String[] args) throws Exception{
    Connection con = DriverManager.getConnection(url, user, pass);
    Configuration hcfg=new Configuration();
    hcfg=hcfg.configure(new File("hcfg.xml"));
    SessionFactory fact= hcfg.buildSessionFactory();      
    Session session = fact.openSession(con);

    Department dept = new Department("d1");
    Employee  emp=new Employee("e1", 9000);      
    Employee  emp2=new Employee("e2", 8900);
    dept.addEmployee(emp);
    dept.addEmployee(emp2);      
    // Note  dept.addEmployee()  sets the relationship for both ends
    session.save(dept);

    //  *** Problem ***
    // employees  are not saved to database (hibernated issues "update"
    // sql instead of insert).  They're not saved even if you add:
    session.save(emp);  session.save(emp2);      

    session.flush();
}



Thanx again.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 11, 2004 2:56 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Enable the Hibernate log and check why Hibernate thinks it has to update. Are you sure you need assigned identifiers?

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 11, 2004 6:40 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
Thanx for replying. The assinged Id's are a requirement, but it didn't appreat to work with uuid's either.
As to loggin, is the following sufficient ? I did notice it logs "processing one-to-one association" even though the config file didn't define any 1-to-1 relationships.

Also tried running the debugger, but for some reason seems it shows the wrong lines of code.
Thanx again.

Code:
11/05/2004 13:28:48 net.sf.hibernate.cfg.Environment <clinit>
INFO: Hibernate 2.1.2
11/05/2004 13:28:48 net.sf.hibernate.cfg.Environment <clinit>
INFO: hibernate.properties not found
11/05/2004 13:28:48 net.sf.hibernate.cfg.Environment <clinit>
INFO: using CGLIB reflection optimizer
11/05/2004 13:28:48 net.sf.hibernate.cfg.Configuration configure
INFO: configuring from file: hcfg.xml
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration addFile
INFO: Mapping file: empCfg.xml
11/05/2004 13:28:49 net.sf.hibernate.cfg.Binder bindRootClass
INFO: Mapping class: test.Employee -> Employee
11/05/2004 13:28:49 net.sf.hibernate.cfg.Binder bindRootClass
INFO: Mapping class: test.Department -> Dept
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration doConfigure
INFO: Configured SessionFactory: null
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration secondPassCompile
INFO: processing one-to-many association mappings
11/05/2004 13:28:49 net.sf.hibernate.cfg.Binder bindCollectionSecondPass
INFO: Mapping collection: test.Department.employees -> Employee
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration secondPassCompile
INFO: processing one-to-one association property references
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
11/05/2004 13:28:49 net.sf.hibernate.dialect.Dialect <init>
INFO: Using dialect: net.sf.hibernate.dialect.Oracle9Dialect
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: Use outer join fetching: true
11/05/2004 13:28:49 net.sf.hibernate.connection.UserSuppliedConnectionProvider configure
WARNING: No connection properties specified - the user must supply JDBC connections
11/05/2004 13:28:49 net.sf.hibernate.transaction.TransactionManagerLookupFactory getTransactionManagerLookup
INFO: No TransactionManagerLookup configured (in JTA environment, use of process level read-write cache is not recommended)
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: Use scrollable result sets: false
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: Use JDBC3 getGeneratedKeys(): false
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: Optimize cache for minimal puts: false
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: echoing all SQL to stdout
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: Query language substitutions: {}
11/05/2004 13:28:49 net.sf.hibernate.cfg.SettingsFactory buildSettings
INFO: cache provider: net.sf.ehcache.hibernate.Provider
11/05/2004 13:28:49 net.sf.hibernate.cfg.Configuration configureCaches
INFO: instantiating and configuring caches
11/05/2004 13:28:49 net.sf.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory
11/05/2004 13:28:50 net.sf.hibernate.impl.SessionFactoryObjectFactory addInstance
INFO: no JNDI name configured



Top
 Profile  
 
 Post subject:
PostPosted: Tue May 11, 2004 6:44 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
This is the initialization log, it is useless for this problem. You need the log in DEBUG mode that is written when session.flush() is executed. Please don't post it, read it and try to understand it.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 12, 2004 12:36 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
The debug messages were not of little help, i'm afraid. It does say it found "3 new insertions", yet only the parent is saved to the DB.
However, I've noticed the problem only occurs if you add children before saving the parent. Namely:

The following works:
Code:
Department dept=new Department("d1");
Employee e1=new Employee(...)
Employee e2=new Employee(...)
session.save(dept);                  // Save parent first
dept. add (new Employee(...))  //  Then add children
dept. add (new Employee(...))
session.save(e1);   // save children (here, one is not taking
session.save(e2);  // advantage of cascade-saving)


While the following fails if you use cascade=all (employees aren't saved):
Code:
Department dept=new Department("d1");
Employee e1=new Employee(...)
Employee e2=new Employee(...)
dept. add (new Employee(...))  // First add children
dept. add (new Employee(...)) 
session.save(dept);                 // Then save parent
session.save(e1);     // shouldn't be required with cascade=all,
session.save(e2);    // but id doesn't work even with explicit save



IMHO, that does indicate a problem: inconsistent behaviour is usually considered a bug.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 13, 2004 12:19 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
Sorry, forgot to mention that *bofore* flushing, when saving department, the log says employees are already saved & that's why it only issues an "update". Of course, this is not surprising.
For instance, that's the interesting part of the log for employee "e2":

17:20:44,514 DEBUG SessionImpl:807 - saving [test.Department#d1]
17:20:44,524 DEBUG Cascades:497 - processing cascades for: test.Department
17:20:44,524 DEBUG Cascades:506 - done processing cascades for: test.Department
17:20:44,524 DEBUG Cascades:497 - processing cascades for: test.Department
17:20:44,524 DEBUG Cascades:524 - cascading to collection: test.Department.employees
17:20:44,534 DEBUG Cascades:113 - cascading to saveOrUpdate()
17:20:44,534 DEBUG Cascades:341 - id unsaved-value strategy NULL
17:20:44,534 DEBUG SessionImpl:1363 - saveOrUpdate() previously saved instance with id: e2
17:20:44,534 DEBUG SessionImpl:1411 - updating [test.Employee#e2]


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 13, 2004 12:40 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
17:20:44,534 DEBUG Cascades:113 - cascading to saveOrUpdate()
17:20:44,534 DEBUG Cascades:341 - id unsaved-value strategy NULL
17:20:44,534 DEBUG SessionImpl:1363 - saveOrUpdate() previously saved instance with id: e2

You can't use an unsaved-value with assigned identifiers (a bad idea anyway). Set the "unsaved-value" on a <version>/<timestamp> mapping or implement an Interceptor that evaluates isUnsaved() for each object.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 13, 2004 4:43 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
Thanx a lot, it solved it.

Let me please ask, though: is this really considered a feature ?
Naively speaking, I'd have expected the exmple to work even with assigned IDs. Or at least issue some warning. Even experienced users haven't spotted the problem at first glance...
Not looking for a long answer, of course, but i'd be glad to hear if there's any inherent problem with it, which can be described in 1-2 sentences, or in some published hibernate policy paper.

Thanks again.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 13, 2004 4:54 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Assigned identifiers are rare and a special case.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 16, 2004 1:04 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
Please consider, isn't this statement a bit too strong ? IT systems may key people by social security numbers, vehicles by license numbers, products by ISBN obtained from legacy systems, etc.
One can't always introduce synthetic(surrogate) keys, nor timestamp/version columns: the project for which we're currently considering Hibernate connects to an existing DB, and tables are not to be altered since (1) they're still accessed by old legacy systems and (2) tables are not under our control (located on customers' machines & maintained by them) . This is quite a common situation in the industry.
Lack of a timestamp column is not as common, but it's not all that rare either, especially for "constant" tables (e.g. information of countries, languages, constant status codes, etc).
To sum it up, could you kindly let me know if you'd recommend Hibernate given such conditions : assigned ID's , not guarantee for timestamp/version column, yet still requiring cascading 1:M relationships.

Thank you very much in advance.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 16, 2004 4:35 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
No problem for Hibernate, but more work for you to set it up. Not much more, though, but tricky sometimes. Natural keys, as you describe them, are not neccessarily application assigned keys, by the way. A stored procedure and a trigger could also be used.

I insist that these cares _are_ rare, to get people thinking and not encouraging this practice. Use surrogate keys.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 16, 2004 5:17 am 
Beginner
Beginner

Joined: Tue May 11, 2004 12:20 am
Posts: 33
thank u very much for the time & effort.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 21, 2004 8:11 am 
Newbie

Joined: Thu Apr 29, 2004 11:15 pm
Posts: 8
hi i meet the same question but in my mapping files
this three table has the seqence primary key themseves.
so how to handle the cascade of the same question.
cant insert but update the middle table .


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.