-->
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.  [ 5 posts ] 
Author Message
 Post subject: How to create an association without SELECTing the referent
PostPosted: Thu Mar 29, 2007 12:59 pm 
Newbie

Joined: Fri Sep 15, 2006 11:35 am
Posts: 3
Hi, I'm trying to improve performance a bit in a perhaps slightly unique circumstance, and I'm wondering if there's a way to make Hibernate do what I need.

I am creating new records in table A, which contains many foreign keys referring to various other tables. All of the Hibernate mappings are in place and working fine. The data that I receive and which I use to create the new record to insert provides me with all of the FK values I need. In order to insert these records via Hibernate, I'm currently doing something like:

Code:
A myA = new A();
// ...
Foo aFoo = session.load(Foo.class, theFooId);
myA.setFoo(aFoo);
// ...
session.save(myA);


with the middle section repeated many times for the various referenced objects. This works fine, but it's not very efficient because it requires Hibernate to load each referenced object. What I'd really like is to be able to do something like:

Code:
A myA = new A();
//...
myA.setFoo(new Foo(theFooId));
//...
sesion.save(myA);


And then somehow tell Hibernate that when myA is saved, it should not try to update the associated Foo record, but just store myA with the FK from theFooId. The database will, of course, ensure referential integrity.

Of course, I could just ignore Hibernate and do this directly via JDBC, but there is other stuff I need to do on the A instance that makes such an approach inconvenient enough that I'd rather just eat the performance hit of the extra SELECTs. Ideally, of course, I want to use Hibernate and avoid the unnecessary SELECTs.

Any ideas?

Thanks,

Shawn.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 29, 2007 6:22 pm 
Red Hat Associate
Red Hat Associate

Joined: Mon Aug 16, 2004 11:14 am
Posts: 253
Location: Raleigh, NC
Have you logged the SQL and seen this happening? If you're in the same session the load will happen only once because of the L1 cache. If the entity your referring to is lazy (default in 3.x), the load won't happen at all since the PK is already there.

-Chris


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 29, 2007 10:30 pm 
Newbie

Joined: Fri Sep 15, 2006 11:35 am
Posts: 3
Yes it would be nice if it weren't a problem, wouldn't it? :-)

No, the objects have not been previously loaded in the session. The session begins just before the "A" is created and ends just after it is saved. This is a web service whose sole purpose is to create the object in question.

And, yes, I normally develop with show_sql on, and the objects are always being SELECTed. There are almost 20 relations that have to be SELECTed per create operation so it's a significant performance penalty.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 30, 2007 8:32 am 
Red Hat Associate
Red Hat Associate

Joined: Mon Aug 16, 2004 11:14 am
Posts: 253
Location: Raleigh, NC
Then if you want someone to diagnose the issue, you'll have to post all the information asked for when you clicked "new topic". Code, mapping files, etc.

-Chris


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 30, 2007 10:33 am 
Newbie

Joined: Fri Sep 15, 2006 11:35 am
Posts: 3
I can't post the code and mapping files, for the typical reasons. However, they're not really necessary as I'm not looking for someone to diagnose a defect. There's nothing going wrong, Hibernate is operating correctly.

What I'm looking for is a technique, perhaps some element of the Hibernate API I've overlooked, some clever use of interceptors or event listeners, etc., that will allow me to insert a new record into a table that has many-to-one references to other tables, but without having to first SELECT the referents.

If it helps, here's a simplified scenario. Assume the following classes:

Code:
public class A
{
    private Integer key;
    private B b;

    public Integer getKey() { return key; }
    public void setKey(Integer key) { this.key=key; }
    public B getB() { return b; }
    public void setB(B b) { this.b = b; }
};


Code:
public class B
{
    private Integer key;
    private String value;

    public Integer getKey() { return key; }
    public void setKey(Integer key) { this.key=key; }
    public String getValue() { return value; }
    public void setValue() { this.value = value; }
}


And the following mappings

Code:
<hibernate-mapping>
  <class name="A">
    <id name="key"/>
    <many-to-one name="b"/>
  </class>
  <class name="B">
    <id name="key"/>
    <property name="value"/>
  </class>
</hibernate-mapping>


And, finally, the method I'm trying to implement:

Code:
public createA(Integer bKey)
{
    A a = new A();
    a.setB(session.load(B.class, bKey)); // Here's the question
    session.save(a);
}


Now, what I would like to have Hibernate do is issue the following:

Code:
INSERT INTO A (B) VALUES (?)


Where "bKey" is substituted for the parameter. What Hibernate does, of course is issue:

Code:
SELECT KEY,VALUE FROM B WHERE KEY=?
INSERT INTO A (B) VALUES (?)


where "bKey" is substituted for both parameters. That makes sense -- after all I did tell Hibernate to "load" the B instance -- but I want to avoid that extra SELECT statement. So, how can I associate the B instance with the new A instance without actually loading the B?

Of course, in this trivial example, the best approach would be to bypass Hibernate and simply use JDBC, or else create an alternative mapping of A that models the B relationship as a property, rather than a relationship. Something like:

Code:
public class DirectA
{
    private Integer key;
    private Integer bKey;

    public Integer getKey() { return key; }
    public void setKey(Integer key) { this.key=key; }
    public Integer getBKey() { return bKey; }
    public void setBKey(Integer bKey) { this.bKey = bKey; }
};


Code:
<hibernate-mapping>
  <class name="DirectA" table="A">
    <id name="key"/>
    <property name="bKey" column="B"/>
  </class>
</hibernate-mapping>


Then I could write:

Code:
public createA(Integer bKey)
{
    DirectA directA = new DirectA();
    directA.setBKey(bKey);
    session.save(directA);
}


But the real-world case is not nearly so trivial. In fact, my 'A' class is rather large and complex and has many many-to-one mappings to other classes. That being the case, maintaining a separate mapping is an undesirable maintenance burden. Perhaps one I'll have to accept if I can't find another way, but undesirable.

My question then, is: Is there a way to avoid the extra SELECT without creating the additional mapping, and without bypassing Hibernate?

Thanks,

Shawn.


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