-->
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.  [ 9 posts ] 
Author Message
 Post subject: Ternary Associations are baffling me!
PostPosted: Sun Apr 04, 2004 2:11 am 
Newbie

Joined: Sun Apr 04, 2004 1:58 am
Posts: 13
Location: Melbourne, Australia
I have a simple ternary association I would like to persist and query
involving 3 persitable objects - Image, Author and Contribution. I
also have a type to represent an association, my AuthorContribution
type.

I don't really care if I use a Set, Map, composite-element or anything
else to represent this relationship.

I have a table that represents the association between the three
object (IMAGE_AUTHOR_CONTRIBUTION).

The problem is the association table (IMAGE_AUTHOR_CONTRIBUTION) is never updated althought each of the classes (IMAGE, AUTHOR, CONTRIBUTION) write to the database successfully!

Also, I was also expecting that during the creation of the
IMAGE_AUTHOR_CONTRIBUTION table that a primary key of (IMAGE_ID,
AUTHOR_ID, CONTRIBUTION_ID) would have been created and instead there
was no primary key.

Any help would be GREATLY appreciated.

I am using Hibernate 2.1, hsqldb v1.7.1

Here is the code I use to persist my data:

Code:
        Image image = new Image( "Mona Lisa" );
        Author author = new Author( "Leonardo De Vinci" );
        Contribution contribution = new Contribution( "Painter" );

        AuthorContribution ac = new AuthorContribution( author, contribution );
        Set acs = new HashSet();
        acs.add( ac );
        image.setAuthorContributions( acs );

        Session session = sessions.openSession();
        session.save( contribution );
        session.save( author );
        session.save( image );
        session.close();


Here are my mapping files:

--- (Image.hbm.xml)
Code:
    <class name="Image" table="IMAGE">
        <id name="id" column="IMAGE_ID" type="java.lang.Integer" unsaved-value="-99">
            <generator class="native"/>
        </id>
        <set name="authorContributions" table="IMAGE_AUTHOR_CONTRIBUTION" inverse="false" cascade="all">
            <key column="IMAGE_ID" />
            <composite-element class="AuthorContribution">
                <many-to-one name="author" class="Author" column="AUTHOR_ID"/>
                <many-to-one name="contribution" class="Contribution" column="CONTRIBUTION_ID"/>
            </composite-element>
        </set>
        <property name="name" type="java.lang.String" column="NAME" not-null="true"/>
    </class>


--- (Author.hbm.xml)
Code:
    <class name="Author" table="AUTHOR">
        <id name="id" column="AUTHOR_ID" type="java.lang.Integer" unsaved-value="-99">
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String" column="NAME" not-null="true"/>
    </class>


--- (Contribution.hbm.xml)
Code:
    <class name="Contribution" table="CONTRIBUTION">
        <id name="id" column="CONTRIBUTION_ID" type="java.lang.Integer" unsaved-value="-99" >
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String" column="NAME" not-null="true" />
    </class>


Here are my java files:

--- (Image.java)
Code:
public class Image
{
    protected Integer id = new Integer( 0 );
    protected String name;
    protected Set authorContributions;

    private Image() { }
    public Image( String name ) { this.name = name; }
    public Set getAuthorContributions() { return authorContributions; }
    public void setAuthorContributions( Set authorContributions ) { this.authorContributions = authorContributions; }
    public Integer getId() { return id; }
    public void setId( Integer id ) { this.id = id; }
    public String getName() { return name; }
    public void setName( String name ) { this.name = name; }

    public boolean equals( Object o )
    {
        if( this == o ) return true;
        if( !( o instanceof Image ) ) return false;

        final Image image = ( Image ) o;

        if( !authorContributions.equals( image.authorContributions ) ) return false;
        if( !name.equals( image.name ) ) return false;

        return true;
    }

    public int hashCode()
    {
        int result;
        result = name.hashCode();
        result = 29 * result + authorContributions.hashCode();
        return result;
    }
}


--- (Author.java)
Code:
import java.util.Set;

public class Author
{
    protected Integer id = new Integer( 0 );
    protected String name;

    private Author(){}
    public Author( String name ) { this.name = name; }
    public Integer getId() { return id; }
    public void setId( Integer id ) { this.id = id; }
    public String getName() { return name; }
    public void setName( String name ) { this.name = name; }
    public boolean equals( Object o )
    {
        if( this == o ) return true;
        if( !( o instanceof Author ) ) return false;

        final Author author = ( Author ) o;

        if( !name.equals( author.name ) ) return false;

        return true;
    }

    public int hashCode() { return name.hashCode(); }
}


--- (Contribution.java)
Code:
import java.util.Set;

public class Contribution
{
    protected Integer id = new Integer( 0 );
    protected String name;

    private Contribution(){}
    public Contribution( String name ) { this.name = name; }
    public Integer getId() { return id; }
    public void setId( Integer id ) { this.id = id; }
    public String getName() { return name; }
    public void setName( String name ) { this.name = name; }
    public boolean equals( Object o )
    {
        if( this == o ) return true;
        if( !( o instanceof Contribution ) ) return false;

        final Contribution author = ( Contribution ) o;

        if( !name.equals( author.name ) ) return false;

        return true;
    }

    public int hashCode() { return name.hashCode(); }
}


--- (AuthorContribution.java)
Code:
public class AuthorContribution
{
    protected Author author;
    protected Contribution contribution;

    private AuthorContribution() { }

    public AuthorContribution( Author author, Contribution contribution )
    {
        this.author = author;
        this.contribution = contribution;
    }

    public Author getAuthor() { return author; }
    public void setAuthor( Author author ) { this.author = author; }
    public Contribution getContribution() { return contribution; }
    public void setContribution( Contribution contribution ) { this.contribution = contribution; }

    public boolean equals( Object o )
    {
        if( this == o ) return true;
        if( !( o instanceof AuthorContribution ) ) return false;

        final AuthorContribution authorContribution = ( AuthorContribution ) o;

        if( !author.equals( authorContribution.author ) ) return false;
        if( !contribution.equals( authorContribution.contribution ) ) return false;

        return true;
    }

    public int hashCode()
    {
        int result;
        result = author.hashCode();
        result = 29 * result + contribution.hashCode();
        return result;
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 06, 2004 1:30 am 
Newbie

Joined: Sun Apr 04, 2004 1:58 am
Posts: 13
Location: Melbourne, Australia
If this question is unclear please let me know and I will rephrase it.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 07, 2004 6:32 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
This should work AFAIK, give more info (log).
Have a look at http://www.hibernate.org/109.html just in case.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 08, 2004 5:18 am 
Newbie

Joined: Sun Apr 04, 2004 1:58 am
Posts: 13
Location: Melbourne, Australia
Hi Emmanuel,

Thanks for the response. I really appreciate any time you can give here.

Now here is the strange thing. I simply added a session.flush() and the IMAGE_AUTHOR_CONTRIBUTION table was updated.

Code:
        Image image = new Image( "Mona Lisa" );
        Author author = new Author( "Leonardo De Vinci" );
        Contribution contribution = new Contribution( "Painter" );

        AuthorContribution ac = new AuthorContribution( author, contribution );
        Set acs = new HashSet();
        acs.add( ac );
        image.setAuthorContributions( acs );

        Session session = sessions.openSession();
        session.save( contribution );
        session.save( author );
        session.save( image );
        session.flush();            //  <---- HERE!!!
        session.close();


I read the equals()/hashcode() page and I think I am doing everything correctly - I've included the equals and hashcode methods in the original post and all they are doing is checking for equality on the 'name' attribute of each class. Nothing fancy.

I also tried removing any reference to AuthorContribution from the equals and hashcode methods of Image class, but that made no difference.

So... Is flush necessary or have I make a mistake somewhere?

Mark


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 08, 2004 5:27 am 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
?????
where is the commit?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 08, 2004 8:50 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
This is the correct behavior
An impelmentation detail force Hibernate to do the insert of entities wo explicit request.
Since you don't use hibernate tx.commit() you need to explicitly flush before closing.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 12, 2004 8:00 pm 
Newbie

Joined: Sun Apr 04, 2004 1:58 am
Posts: 13
Location: Melbourne, Australia
Emmanuel,

Thanks for the clarification. Either surrounding the action in a transaction or calling flush works like a treat. I've decided to surround the action in a transaction.

Thanks for taking the time to look at this.

Mark


Top
 Profile  
 
 Post subject: Same problem, but with a map
PostPosted: Wed Mar 11, 2009 4:41 am 
Newbie

Joined: Wed Mar 11, 2009 4:37 am
Posts: 9
Hi all,

I've stumbled upon the same problem as emmanuel, only 5 years later. I don't understand why a flush / commit is necessary to persist the ternary association to the database (in his case, stored in the table IMAGE_AUTHOR_CONTRIBUTION). Can anyone explain?

Thanks,
Andrei


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 6:25 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
This is how Hibernate works. It has nothing to do with the ternary association as such. Hibernate keep things in memory until there is a reason to synchronize with the database.
flush() or commit() are examples of such reasons. The save() method is an exception to the general rule. Depending on what kind of id generator you are using it may trigger an insert into the database, or it may not. In any case, the insert doesn't mean that other updates also happen.

For example, if markmansour had used the 'assigned' id generator instead of 'native' the save() wouldn't have triggered an insert and without the flush() nothing would have been inserted.

See http://www.hibernate.org/hib_docs/v3/re ... shing.html


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.