tags:

views:

65

answers:

3

I have two tables: foo (primary key: foo_id) and foo_entry (primary key: foo_entry_id; foreign key: foo_id).

Below is my Hibernate config.
My problem is, when I call getAttributes() on the FooModel class, I end up with a list of a little over one million null objects. (foo table has ~200 rows, foo_entry has ~10,000).

I'm new to Hibernate and suspect I am just overlooking or am just not understanding something very, very basic. Any help appreciated!

<hibernate-mapping package="com.blah.www">
  <class name="FooModel" table="foo">
    <id name="fooId" column="foo_id"></id>

    <list name="attributes" table="foo_entry">
      <key column="foo_id" />
      <index column="entry_id" />
      <one-to-many class="FooEntryModel" />
    </list>
  </class>
</hibernate-mapping>

<hibernate-mapping package="com.blah.www">
  <class name="FooEntryModel" table="foo_entry">
    <id name="fooEntryId" column="foo_entry_id">
      <generator class="native" />
    </id>

    <property name="fooId"      type="int"       column="foo_id"      /> 
    <property name="attrName"   type="string"    column="attr_name"   />
    <property name="attrValue"  type="string"    column="attr_value"  />
    <property name="startDate"  type="timestamp" column="start_date"  /> 
    <property name="endDate"    type="timestamp" column="end_date"    />
  </class> 
</hibernate-mapping>
+2  A: 

The numbers imply you're getting a Cartesian join. Do you have the FK set up in the database?

aside - I used Hibernate for a a year and never coded an attribute-infused model or one of those files like your show. We always reverse-engineered the database.

Tony Ennis
*slaps forehead*. Yes, I did not have the FK set up in the database. Doing so solved my problem, thank you!
Aaron F.
@Aaron F.: BTW, setting up a foreign key in the database is not mandatory. We sometimes don't do that in development and test schemas. Unless you are reverse-engineering.
Adeel Ansari
setting up the FK only enforces the constraint on valid data - doesn't affect what the query will return
matt b
that's definitely not what I'm seeing; adding the FK made the same code suddenly performant. I'll double-check
Aaron F.
curiously enough -- adding the FK did *not* eliminate the "list of 1-million null objects" problem. But it did eliminate the OOM problem.
Aaron F.
I figured this out, see my posted answer.
Aaron F.
+2  A: 

First step to debug is to see the query, Hibernate generated for you, in the logs. However, I suggest you to try this,

<list name="attributes">
  <key column="foo_id" />
  <one-to-many class="FooEntryModel" />
</list>

Adeel Ansari
Yes! Eliminating the "<index column="entry_id" />" entry wasn't allowed. But eliminating the "table="foo_entry"" attribute from the <list> tag *did* eliminate the "list of 1-million null objects" problem. Curious as to why.
Aaron F.
Per http://docs.jboss.org/hibernate/core/3.3/reference/en/html/collections.html, for the <list> tag, the "table" attribute is documented as: "(optional - defaults to property name): the name of the collection table. It is not used for one-to-many associations." ... if it's not used for one-to-many associations, then maybe Hibernate should throw a compile-time error if <list> contains a <one-to-many> tag... ??
Aaron F.
@Aaron: Couldn't really get you here. Having a `<one-to-many>` tag inside `<list>` is legal. The docs merely stating that the `table` attribute of `<list>` element is not used for `one-to-many` associations. Because, we need a `class` to define the relationship, table name wouldn't do it.
Adeel Ansari
I figured this out, see my posted answer.
Aaron F.
A: 

Sigh...

This turned out to have a very logical (and very subtle) explanation. I had misunderstood and hijacked the semantics of the <index> (also known as <list-index>) tag within <list>. Namely, given:

<list name="attributes">
    <key column="foo_id" />
    <index column="some_integer_value" />
    <one-to-many class="FooEntryModel" />
</list>

... I thought was referring to the attribute by which you want to order the list. In fact, it refers to an attribute whose value denotes at what index position within the list to insert the overall object. It's meant to be a placeholder attribute, maintained and used entirely by Hibernate.

The value of the "some_integer_value" to which I was mapping varied in my test data. Sometimes the value was less than a 100. Sometimes it was greater than a million.

Thus, upon mapping just one row where "some_integer_value" == e.g. 100,001, Hibernate would create a list with that object inserted in the 100,001st position. Every list member preceding it, naturally, would be null.

Aaron F.