-->
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: Ordering saves when using transitive persistence
PostPosted: Tue Feb 17, 2009 8:03 pm 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
Hibernate version: 3.3.1.GA

I am trying to use transitive persistence to save three related entity objects. The parent object is Organization, and it has a parent/child relationship to both OrganizationAddress entities and Contact entities. The mapping is below.

Organization
Code:
    /**
     * The contacts for this organization
     */
    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "organization")
    @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Set<Contact> contacts = new HashSet<Contact>();

    /**
     * The addresses of the organization's offices
     */
    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "organization")
    @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Set<OrganizationAddress> locations = new HashSet<OrganizationAddress>();


OrganizationAddress
Code:
    @ManyToOne
    @JoinColumn(name = "organization_id", nullable = false)
    private Organization organization;


Contact
Code:
    /**
     * The contact's address
     */
    @ManyToOne
    @JoinColumn(name = "organization_address_id", nullable = false)
    private OrganizationAddress address = new OrganizationAddress();

    /**
     * The {@link Organization} that the contact belongs to
     */
    @ManyToOne
    @JoinColumn(name = "organization_id")
    private Organization organization;


Finally, the code I use to save the entire object graph is:

Code:
    session.beginTransaction();
    session.save(organization);
    session.flush();
    session.getTransaction().commit();


Everything works as it should unless I try to save a transient Contact with a transient OrganizationAddress. When I do, the save fails with the following stack trace.

Quote:
org.hibernate.PropertyValueException: not-null property references a null or transient value: net.seamist.organization.Contact.address
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:534)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:526)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:241)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at net.seamist.ui.OrganizationFrameController.saveOrganization(OrganizationFrameController.java:227)
at net.seamist.ui.OrganizationFrame.saveOrganization(OrganizationFrame.java:1044)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jdesktop.application.ApplicationAction.noProxyActionPerformed(ApplicationAction.java:662)
at org.jdesktop.application.ApplicationAction.actionPerformed(ApplicationAction.java:698)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
at java.awt.Component.processMouseEvent(Component.java:6134)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5899)
at java.awt.Container.processEvent(Container.java:2023)
at java.awt.Component.dispatchEventImpl(Component.java:4501)
at java.awt.Container.dispatchEventImpl(Container.java:2081)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
at java.awt.Container.dispatchEventImpl(Container.java:2067)
at java.awt.Window.dispatchEventImpl(Window.java:2458)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)



Obviously Hibernate is trying to save the Contact object before saving the OrganizationAddress object, which in turn is causing the exception. Is there a way for me to specify the order of the saves? or is there a better way to map the classes?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 4:13 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Specify a cascade for the @ManyToOne on Contact.address.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 11:23 am 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
Thank you for the suggestion. I did as you said, but am now getting a different exception. Here is the new mapping for Contact.address.

Code:
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinColumn(name = "organization_address_id", nullable = false)
private OrganizationAddress address = new OrganizationAddress();


And here is the new exception.

Quote:
org.hibernate.PropertyValueException: not-null property references a null or transient value: net.seamist.organization.Contact.address
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:534)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:526)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:241)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at net.seamist.ui.OrganizationFrameController.saveOrganization(OrganizationFrameController.java:227)
at net.seamist.ui.OrganizationFrame.saveOrganization(OrganizationFrame.java:1044)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jdesktop.application.ApplicationAction.noProxyActionPerformed(ApplicationAction.java:662)
at org.jdesktop.application.ApplicationAction.actionPerformed(ApplicationAction.java:698)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
at java.awt.Component.processMouseEvent(Component.java:6134)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5899)
at java.awt.Container.processEvent(Container.java:2023)
at java.awt.Component.dispatchEventImpl(Component.java:4501)
at java.awt.Container.dispatchEventImpl(Container.java:2081)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
at java.awt.Container.dispatchEventImpl(Container.java:2067)
at java.awt.Window.dispatchEventImpl(Window.java:2458)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


Any help would be appreceiated. Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 11:33 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
Are you sure your address is not null, when you save it?

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 12:23 pm 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
Yes I am. I just checked to make sure. Before session.save(organization) is called, the organization instance is fully populated with the new contact. Furthermore that new contact is populated with the new address.

Does it matter that the many-to-one between contact and address is unidirectional?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 1:01 pm 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
Quote:
/**
* The contact's address
*/
@ManyToOne
@JoinColumn(name = "organization_address_id", nullable = false)
private OrganizationAddress address = new OrganizationAddress();


Did you add a Cascade there, too? You should add cascade to the entire graph you want to save, when saving the root object.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 1:08 pm 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
I did add a cascade to the @ManyToOne after Nordborg suggested it. The revised mapping is listed above.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 2:52 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Quote:
And here is the new exception.

org.hibernate.PropertyValueException: not-null property references a null or transient value: net.seamist.organization.Contact.address
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
....

at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
....



Hmmm... This exception seems to be the same as the one in the first post....
And closer look at this part of the stacktrace seems to indicate that the cascade is going from Organization -> contacts-> Contact -> address.

Unless you already have done so, I think you need to print out some debug information to verify that all contacts really has an address, and it would also be a good idea to turn on Hibernate debugging.

Can you show the code where you are creating the Organization, Contact and OrganizationAddress?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 4:06 pm 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
I have turned on trace level debugging, and have some additional information. Nordborg, I think you are correct in your assumptions regarding the order of cascades.

Quote:
117828 [AWT-EventQueue-0] DEBUG org.hibernate.transaction.JDBCTransaction - begin
117828 [AWT-EventQueue-0] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
117828 [AWT-EventQueue-0] TRACE org.hibernate.connection.DriverManagerConnectionProvider - total checked-out connections: 0
117828 [AWT-EventQueue-0] TRACE org.hibernate.connection.DriverManagerConnectionProvider - using pooled JDBC connection, pool size: 0
117828 [AWT-EventQueue-0] DEBUG org.hibernate.transaction.JDBCTransaction - current autocommit status: true
117828 [AWT-EventQueue-0] DEBUG org.hibernate.transaction.JDBCTransaction - disabling autocommit
117844 [AWT-EventQueue-0] TRACE org.hibernate.jdbc.JDBCContext - after transaction begin
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [net.seamist.organization.Organization#284]
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.AbstractFlushingEventListener - flushing session
117844 [AWT-EventQueue-0] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: net.seamist.organization.Organization
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: net.seamist.organization.Organization.contacts
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [net.seamist.organization.Contact#1]
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.AbstractSaveEventListener - transient instance of: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.DefaultSaveOrUpdateEventListener - saving transient instance
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.AbstractSaveEventListener - saving [net.seamist.organization.Contact#<null>]
117844 [AWT-EventQueue-0] TRACE org.hibernate.event.def.AbstractSaveEventListener - executing insertions
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: net.seamist.organization.Contact
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.VersionValue - version unsaved-value strategy UNDEFINED
117844 [AWT-EventQueue-0] TRACE org.hibernate.engine.IdentifierValue - id unsaved-value: null
117860 [AWT-EventQueue-0] ERROR net.seamist.ui.OrganizationFrameController - Organization save failed
org.hibernate.PropertyValueException: not-null property references a null or transient value: net.seamist.organization.Contact.address
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:534)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:526)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:241)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:319)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:265)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at net.seamist.ui.OrganizationFrameController.saveOrganization(OrganizationFrameController.java:228)
at net.seamist.ui.OrganizationFrame.saveOrganization(OrganizationFrame.java:1044)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jdesktop.application.ApplicationAction.noProxyActionPerformed(ApplicationAction.java:662)
at org.jdesktop.application.ApplicationAction.actionPerformed(ApplicationAction.java:698)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
at java.awt.Component.processMouseEvent(Component.java:6134)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5899)
at java.awt.Container.processEvent(Container.java:2023)
at java.awt.Component.dispatchEventImpl(Component.java:4501)
at java.awt.Container.dispatchEventImpl(Container.java:2081)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
at java.awt.Container.dispatchEventImpl(Container.java:2067)
at java.awt.Window.dispatchEventImpl(Window.java:2458)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


I have already used the Netbeans debugger to verify that the contacts do in fact have addresses. Before session.save() is called with the organization, organization.locations contains the new address. organization.contacts contains the new contact. And contact.address contains the new address as well.

Here is the code that populates the contact's fields. At this point there is already a transient address that was added to the EntityComboBoxModel.
Code:
        contact.getName().setSalutation((String) view.getJComboBox1().getSelectedItem());
        contact.getName().setFirst(view.getJTextField1().getText());
        contact.getName().setAlias(view.getJTextField2().getText());
        contact.getName().setLast(view.getJTextField3().getText());
        contact.setTitle(view.getJTextField10().getText());
        contact.setRemarks(view.getJTextArea1().getText());
        contact.setAttendingNextEvent(view.getJCheckBox3().isSelected());
        EntityComboBoxModel<OrganizationAddress> aModel
                = (EntityComboBoxModel<OrganizationAddress>) view.getJComboBox2().getModel();
        contact.setAddress(aModel.getSelectedEntityInstance());
        contact.setEmail(view.getJTextField9().getText());
        contact.setEwg(view.getJCheckBox1().isSelected());
        contact.setJpag(view.getJCheckBox2().isSelected());
        contact.setWorkPhone((String) view.getJFormattedTextField1().getValue());
        contact.setWorkPhoneDSN((String) view.getJFormattedTextField2().getValue());
        contact.setFax((String) view.getJFormattedTextField3().getValue());
        contact.setFaxDSN((String) view.getJFormattedTextField4().getValue());
        contact.setMobilePhone((String) view.getJFormattedTextField5().getValue());


That transient contact is then passed to an already persistent organization. By this time, the address has already been added to organization.locations. Here is the code that is called when a address is added and when a contact is added.
Code:
    public class OrganizationAddressAddedListener
            implements DefaultEventListener<OrganizationAddress> {

        @Override
        public void handleEvent( DefaultEvent<OrganizationAddress> event ) {
            organization.addLocation(event.getPayload());
            view.getJTable3().setModel(prepareLocationTableModel());
        }

    }

    public class ContactAddedEventListener implements DefaultEventListener<Contact> {

        @Override
        public void handleEvent( DefaultEvent<Contact> event ) {
            organization.addContact(event.getPayload());
            view.getJTable2().setModel(prepareContactTableModel());
        }

    }


Finally, when a user saves the organization the following code is called. This is the only code that actually contains calls to session methods.
Code:
        EntityComboBoxModel<Citizenship> citiModel
                = (EntityComboBoxModel<Citizenship>) view.getJComboBox2().getModel();
        organization.setCitizenship(citiModel.getSelectedEntityInstance());
        organization.setExtendedName(view.getJTextField2().getText());
        organization.setName(view.getJTextField1().getText());
        organization.setRedFlag(view.getJCheckBox2().isSelected());
        organization.setRemarks(view.getJTextArea1().getText());
        EntityComboBoxModel<Source> sModel
                = (EntityComboBoxModel<Source>) view.getJComboBox3().getModel();
        organization.setSource(sModel.getSelectedEntityInstance());
        EntityComboBoxModel<OrganizationType> otModel
                = (EntityComboBoxModel<OrganizationType>) view.getJComboBox1().getModel();
        organization.setType(otModel.getSelectedEntityInstance());
        organization.setUrl(view.getJTextField3().getText());
        organization.setVisaApplicant(view.getJRadioButton1().isSelected());
        organization.setVisaDenied(view.getJRadioButton4().isSelected());
        organization.setVisaEnrollee(view.getJRadioButton2().isSelected());
        organization.setVisaLinerOperator(view.getJCheckBox1().isSelected());
        organization.setVisaParticipant(view.getJRadioButton3().isSelected());
        organization.setVisaTerminated(view.getJRadioButton5().isSelected());
        organization.setVisaUnknown(view.getJRadioButton7().isSelected());
        organization.setVisaWithdrewApplication(view.getJRadioButton6().isSelected());

        Commitment c1 = new Commitment();
        c1.setActualMetricTons((Integer) view.getJFormattedTextField3().getValue());
        c1.setActualSquareFeet((Integer) view.getJFormattedTextField2().getValue());
        c1.setActualTeus((Integer) view.getJFormattedTextField1().getValue());
        c1.setMetricTons((Integer) view.getJFormattedTextField6().getValue());
        c1.setSquareFeet((Integer) view.getJFormattedTextField5().getValue());
        c1.setTeus((Integer) view.getJFormattedTextField4().getValue());
        c1.setRemarks(view.getJTextArea2().getText());
        organization.setStageOneCommitment(c1);

        c1 = new Commitment();
        c1.setActualMetricTons((Integer) view.getJFormattedTextField9().getValue());
        c1.setActualSquareFeet((Integer) view.getJFormattedTextField8().getValue());
        c1.setActualTeus((Integer) view.getJFormattedTextField7().getValue());
        c1.setMetricTons((Integer) view.getJFormattedTextField12().getValue());
        c1.setSquareFeet((Integer) view.getJFormattedTextField11().getValue());
        c1.setTeus((Integer) view.getJFormattedTextField10().getValue());
        c1.setRemarks(view.getJTextArea3().getText());
        organization.setStageTwoCommitment(c1);

        c1 = new Commitment();
        c1.setActualMetricTons((Integer) view.getJFormattedTextField15().getValue());
        c1.setActualSquareFeet((Integer) view.getJFormattedTextField14().getValue());
        c1.setActualTeus((Integer) view.getJFormattedTextField13().getValue());
        c1.setMetricTons((Integer) view.getJFormattedTextField18().getValue());
        c1.setSquareFeet((Integer) view.getJFormattedTextField17().getValue());
        c1.setTeus((Integer) view.getJFormattedTextField16().getValue());
        c1.setRemarks(view.getJTextArea4().getText());
        organization.setStageThreeCommitment(c1);

        try {
            session.beginTransaction();
            session.save(organization);
            session.flush();
            session.getTransaction().commit();
            log.debug("Organization saved successfully");

            /* Fire off the proper event on a successful save. */
            if (newOrganization) {
                fireEventGlobal(new OrganizationAddedEvent(organization));
            } else {
                fireEventGlobal(new OrganizationChangedEvent(organization));
            }
        } catch (RuntimeException e) {
            try {
                log.error("Organization save failed", e);
                session.getTransaction().rollback();
            } catch (RuntimeException ex) {
                log.error("Transaction rollback failed", ex);
            }
        } finally {
            session.close();
        }


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 6:11 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Hmm... the trace seems to indicate that the save doesn't cascade to the address. I am not all that familiar with the various types of cascades, but you have:

Code:
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})


Have you tried to include @Cascade(CascadeType.SAVE_UPDATE)? Note that this is not in the standard javax.persistence package, but in org.hibernate.annotations.

See http://www.hibernate.org/hib_docs/annot ... ec-cascade for the exact syntax.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 18, 2009 6:49 pm 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
That did it! I changed Contact's mapping to include the following:

Code:
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.SAVE_UPDATE)
    @JoinColumn(name = "organization_address_id", nullable = false)
    private OrganizationAddress address = new OrganizationAddress();


and it worked beautifully. Thank you so much! I was about ready to remove the cascades and just handle the saves on my own.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 19, 2009 8:22 am 
Regular
Regular

Joined: Fri Jan 30, 2009 10:10 am
Posts: 74
Location: London
Just out of curiousity, does your application have a use case for deleting an organization?

I suspect that having the OrganizationAddress directly accessible from both the Organization and the Contact is complicating your model.

You're basically providing two paths from a Contact to the OrganizationAddress - one direct, and one via the organization that the Contact belongs to.

--
Stephen Souness


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 19, 2009 11:51 am 
Newbie

Joined: Fri Feb 13, 2009 1:46 pm
Posts: 9
Yes, and I see your point. A simple redesign would simplify both the mappings and the deletion use case. However, deletion is working so that may have to wait.


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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.