-->
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.  [ 8 posts ] 
Author Message
 Post subject: Fetching in a bidirectional association
PostPosted: Thu Jan 26, 2006 11:35 am 
Newbie

Joined: Fri Dec 23, 2005 7:54 am
Posts: 12
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version:
Hibernate 3.1
Mapping documents:


Hi, I don't know if I get it right but...
I am dealing with a simple association between two entities:
Code:
|Server|1------>1..*|Authorities|


then my classes look like:

Code:
public class Server implements java.io.Serializable  {

    public Server(String name, String address) {
        this.name = name;
        this.address = address;
        authorities = new HashSet<Authority>();
    }

    @Id
    public String getName() {
        return name;
    }
    @OneToMany( mappedBy = "server" )
    public Set<Authority> getAuthorities() {
        return authorities;
    }
...
}


public class Authority implements java.io.Serializable  {

    @Id(generate = GeneratorType.IDENTITY)
    @Column(name = "AUTHORITY_ID")
    public int getAuthorityId() {
        return authorityId;
    }


    @ManyToOne(
            cascade = {CascadeType.ALL}
    )
    @JoinColumn(name="SERVER_NAME")
    public Server getServer() {
        return server;
    }
...
}




What I have been trying to do is the following:

Code:

Server s1 = new Server(...);
Authority a1=new Authority();
a1.setServer(s1);

session.save(a1);

Server sFound = session.load(Server.class, s1.getName());

assertNotNull(sFound.getAuthorities());



when I store the Authority a1 the reference to the Server instance s1 is made in the table (through the FK).
What I was expecting is that when loading a Server instance that is referenced by some Authority record (such a1) the authorities Set was filled...
Instead this happens only if I do

Code:

Server s1 = new Server(...);
Authority a1 = new Authority();
a1.setServer(s1);
s1.getAuthorities().add(a1);

session.save(a1);



I have read in Hibernate in action that
"Hibernate doesn't manage persistent associations"

But I was hoping/expecting that this behavior wasn't applying when looking up instances...After all the left outer join is there just for this reason.






Name and version of the database you are using:
HSQLDB 1.8.0
The generated SQL (show_sql=true):

Code:
15:54:41,117 DEBUG SchemaExport:296 - create table AUTHORITIES (AUTHORITY_ID integer generated by default as identity (start with 1), SERVER_NAME varchar(255), DOMAIN_LABEL varchar(255), primary key (AUTHORITY_ID), unique (SERVER_NAME, DOMAIN_LABEL))
15:54:41,129 DEBUG SchemaExport:296 - create table DOMAINS (label varchar(255) not null, primary key (label))
15:54:41,131 DEBUG SchemaExport:296 - create table PROBE_DEFINITIONS (definitionId integer generated by default as identity (start with 1), frequency integer not null, attempts integer not null, timeout integer not null, QUERY_TYPE_CODE integer, AUTHORITY_ID integer, primary key (definitionId), unique (AUTHORITY_ID, QUERY_TYPE_CODE))
15:54:41,134 DEBUG SchemaExport:296 - create table QUERY_TYPES (code integer not null, type varchar(255), primary key (code))
15:54:41,135 DEBUG SchemaExport:296 - create table SERVERS (name varchar(255) not null, address varchar(255), primary key (name))
15:54:41,139 DEBUG SchemaExport:296 - alter table AUTHORITIES add constraint FKAB62A701681F199A foreign key (SERVER_NAME) references SERVERS
15:54:41,143 DEBUG SchemaExport:296 - alter table AUTHORITIES add constraint FKAB62A7013C90BCCD foreign key (DOMAIN_LABEL) references DOMAINS
15:54:41,146 DEBUG SchemaExport:296 - alter table PROBE_DEFINITIONS add constraint FKBDE05F315C3B908A foreign key (AUTHORITY_ID) references AUTHORITIES
15:54:41,153 DEBUG SchemaExport:296 - alter table PROBE_DEFINITIONS add constraint FKBDE05F31F30586ED foreign key (QUERY_TYPE_CODE) references QUERY_TYPES
15:54:41,157  INFO SchemaExport:202 - schema export complete
15:54:41,161  INFO Configuration:1022 - processing extends queue
15:54:41,162  INFO Configuration:1026 - processing collection mappings
15:54:41,164  INFO Configuration:1035 - processing association property references
15:54:41,164  INFO Configuration:1057 - processing foreign key constraints
15:54:41,166  INFO Configuration:1022 - processing extends queue
15:54:41,166  INFO Configuration:1026 - processing collection mappings
15:54:41,167  INFO Configuration:1035 - processing association property references
15:54:41,168  INFO Configuration:1057 - processing foreign key constraints
15:54:41,171  INFO SessionFactoryImpl:353 - Checking 0 named HQL queries
15:54:41,172  INFO SessionFactoryImpl:373 - Checking 0 named SQL queries
Hibernate: insert into DOMAINS (label) values (?)
Hibernate: insert into SERVERS (address, name) values (?, ?)
Hibernate: select server_.name, server_.address as address4_ from SERVERS server_ where server_.name=?
Hibernate: select domain_.label from DOMAINS domain_ where domain_.label=?
Hibernate: insert into AUTHORITIES (SERVER_NAME, DOMAIN_LABEL, AUTHORITY_ID) values (?, ?, null)
Hibernate: call identity()
Hibernate: insert into SERVERS (address, name) values (?, ?)
Hibernate: insert into DOMAINS (label) values (?)
Hibernate: insert into DOMAINS (label) values (?)
Hibernate: insert into AUTHORITIES (SERVER_NAME, DOMAIN_LABEL, AUTHORITY_ID) values (?, ?, null)
Hibernate: call identity()
Hibernate: insert into AUTHORITIES (SERVER_NAME, DOMAIN_LABEL, AUTHORITY_ID) values (?, ?, null)
Hibernate: call identity()
Hibernate: select this_.AUTHORITY_ID as AUTHORITY1_0_2_, this_.SERVER_NAME as SERVER2_0_2_, this_.DOMAIN_LABEL as DOMAIN3_0_2_, server2_.name as name4_0_, server2_.address as address4_0_, domain3_.label as label1_1_ from AUTHORITIES this_ left outer join SERVERS server2_ on this_.SERVER_NAME=server2_.name left outer join DOMAINS domain3_ on this_.DOMAIN_LABEL=domain3_.label where this_.SERVER_NAME=? and this_.DOMAIN_LABEL=?
Hibernate: select this_.AUTHORITY_ID as AUTHORITY1_0_2_, this_.SERVER_NAME as SERVER2_0_2_, this_.DOMAIN_LABEL as DOMAIN3_0_2_, server2_.name as name4_0_, server2_.address as address4_0_, domain3_.label as label1_1_ from AUTHORITIES this_ left outer join SERVERS server2_ on this_.SERVER_NAME=server2_.name left outer join DOMAINS domain3_ on this_.DOMAIN_LABEL=domain3_.label where this_.SERVER_NAME=? and this_.DOMAIN_LABEL=?



[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 26, 2006 12:41 pm 
Newbie

Joined: Wed Dec 14, 2005 6:50 am
Posts: 17
HI,

I try to give you some hints, but i'm not sure if i understood you right.

Try the following:
Code:
Server s1 = new Server(...);
Authority a1=new Authority();
a1.setServer(s1);

session.save(a1);

[b]session.refresh(a1);[/b]
Server sFound = session.[b]get[/b](Server.class, s1.getName());

assertNotNull(sFound.getAuthorities());


with the refresh you force hibernate to refresh it's state from the db. Its not the good way, but if u won't add the As to the Ss its a possible way.
IMO if you just load the s, it won't get loaded from the db since its still in the session.


But before that, ask yourself:
    * Why won't i add the As to the Ss?
    * Do i need to know the As from the Ss?
    * Is this not a parent/child association?


Hope it helps, let me know...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 26, 2006 1:15 pm 
Newbie

Joined: Fri Dec 23, 2005 7:54 am
Posts: 12
Thanks for the short feedback.

Actually calling refresh happens to do the job!

What I haven't had the time to test is if saving an Authority in a session
and loading the Server instance in another one works...

It seems that the problem is just doing everything within the same session (or should I say transaction?) btw.

Another thing that puzzles me is that if the relationship between Authority to Server is not cascaded i.e

Code:
    @ManyToOne(
// no cascade = ALL here...
    )
    @JoinColumn(name="SERVER_NAME")
    public Server getServer() {
        return server;
    }


And then saving every object separately:
Code:
        Authority a1 = new Authority();
        a1.setServer(s1);
        a1.setDomain(d1);

        Domain d2 = new Domain("dom2.");

        Authority a2 = new Authority();
        a2.setServer(s1);
        a2.setDomain(d2);

        //the sneaky lines...
        s1.getAuthorities().add(a1);
        s1.getAuthorities().add(a2);
        //...

        getSession().save(s1);
        getSession().save(d1);
        getSession().save(d2);
        getSession().save(a1);
        getSession().save(a2);

        Server sf = (Server) getSession().load(Server.class,s1.getName());

        assertEquals(2,sf.getAuthorities().size());  //fails: size() is 0



even calling refresh() doesn't work (the test fails).

Hope this time is clearer anyway,

cheers
Francesco


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 27, 2006 5:04 am 
Newbie

Joined: Wed Dec 14, 2005 6:50 am
Posts: 17
Hmm,
I have a question about your primary keys/business keys and your equals/hashcode impl. Can you post that code too?

Here a link to some general info about it: http://www.hibernate.org/109.html (It's the FAQ so maybe you have already read it...)

If you are using generated keys for hashcode/equals you run in the problem of broken sets! I'm not familiar with annotations but @Id(generate = GeneratorType.IDENTITY) seams to be a key generated by hibernate (on you save the authority object).

You can test the following:
Code:
Authority a2 = new Authority();
a2.setServer(s1);
a2.setDomain(d2);

getSession().save(d1);
getSession().save(d2);
getSession().save(a1);
getSession().save(a2);

//the sneaky lines...
s1.getAuthorities().add(a1);
s1.getAuthorities().add(a2);

//...
getSession().save(s1);


(by the way: you have a transaction around this stuff?)

By saving the authorities bevor adding them to the set the keys are assigned and you get a working hashset. But after all this is possibly not a good solution; Because you have always be sure first save, then add.
I see 2 ways out here:

1) Use lists instead of sets (at least for the authorities)
2) Use a business key for equals/hashcode

Rate if it helps :-)
(sorry for my bloody english)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 27, 2006 6:08 am 
Newbie

Joined: Fri Dec 23, 2005 7:54 am
Posts: 12
MMhhh...
I'm not sure I understand what you asked me to try...I have to make the two assignments (server.getAuthorities().add(a1) and a1.setServer(server)) anyway.

Ok,
here are equals() and hashCode() for Authority

Code:

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        final Authority authority = (Authority) o;

        if (!domain.equals(authority.domain)) return false;
        if (!server.equals(authority.server)) return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = server.hashCode();
        result = 29 * result + domain.hashCode();
        return result;
    }


and here are the ones for Server

Code:
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        final Server server = (Server) o;

        if (!address.equals(server.address)) return false;
        if (authorities != null ? !authorities.equals(server.authorities) : server.authorities != null) return false;
        if (!name.equals(server.name)) return false;

        return true;
    }

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


now that I look at it I'm not really sure that testing over authorities is correct.
Btw, yes I am using business keys to implement them. So AFAIK it's right as described in the FAQ...

Ah, yes, there's a transaction around the session:P

Correct me if i'm wrong:
Is it true that when I call session.save(a1) a record is added into the
AUTHORITIES table with the content

Code:
|   SERVER_NAME   |   DOMAIN_LABEL   |
------------------------------------------------
|  "a server name"  |  "a domain label"   |
------------------------------------------------


Where "a server name" references a record in the SERVERS table
(being SERVER.name the PK)
??

Because if it's like this then calling session.load should be able to navigate through the FK link between SERVER and AUTHORITIES...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 27, 2006 7:15 am 
Newbie

Joined: Fri Dec 23, 2005 7:54 am
Posts: 12
Ok, I've tried and (quite obviously) the set is loaded if I
-save
-commit
-load

Could it be a caching issue then?!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 27, 2006 9:24 am 
Expert
Expert

Joined: Tue Nov 23, 2004 7:00 pm
Posts: 570
Location: mostly Frankfurt Germany
Hello,

if you have a bi-directional relation you must set the relation on both side or your objects in the session could differ from your database entries.

a.getBs().add(b);
sesion.save(a);

could save a to your db (and even b when you cascade) but it will not update the b object in the session or in the cache.
=>
b.getA() will be null.

Regards Sebastian

_________________
Best Regards
Sebastian
---
Training for Hibernate and Java Persistence
Tutorials for Hibernate, Spring, EJB, JSF...
eBook: Hibernate 3 - DeveloperGuide
Paper book: Hibernate 3 - Das Praxisbuch
http://www.laliluna.de


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 2:01 am 
Newbie

Joined: Wed Dec 14, 2005 6:50 am
Posts: 17
Within a session authority.getServer() should work fine. For the rest, im at the end of my latin... sorry


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