views:

583

answers:

1

Hi,

I'm trying to map some existing tables with Hibernate.

It's quite simple: we've got categories that have names in multiple languages.

The DDL is as follows:

create table language (
   id                integer not null auto_increment,
   code              varchar(2) not null,

   unique (code),

   primary key(id)
);

create table category (
   id               integer not null auto_increment,
   parent_id        integer default null,
   ordr             integer not null default 99,

   primary key (id)
);

create table category_description (
   category_id      integer not null,
   language_id      integer not null,

   title            varchar(255) not null,

   constraint foreign key (category_id) references category(id),
   constraint foreign key (country_language_id) references country_language(id),

   primary key (category_id, country_language_id)
);

Now I'd like to have a map with Language as it's key and Description (table category_description) as it's value, like this:

private Map<Language, CategoryDescription> descriptions = new HashMap<Language, CategoryDescription>();

Can anyone provide me with some pointers on this? I've tried the example as given on page 311/312 from the 'Java Persistence with Hibernate' which resembles my problem but I'm just not getting it :(

A: 

(Your DDL is inconsistent, you create a table "language" but reference a table "country_language" -- I will assume the latter)

Here is what the Hibernate mapping for your sample would look like:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt;
<hibernate-mapping default-lazy="false">

 <class name="Language" table="country_language">
  <id name="id" type="int">
   <column name="ID" />
   <generator class="native" />
  </id>
  <property name="code" type="string" length="2" unique="true" />
 </class>

 <class name="Category" table="category">
  <id name="id" type="int">
   <column name="ID" />
   <generator class="native" />
  </id>
  <map name="descriptions" table="category_description">
   <key column="category_id" />
   <map-key-many-to-many column="language_id" class="Language" />
   <composite-element class="CategoryDescription">
    <property name="title" type="string" length="255" />
   </composite-element>
  </map>
 </class>

</hibernate-mapping>

However, you don't need the CategoryDescription class at all (as it just wraps a String):

private Map<Language, String> descriptions;

and

<map name="descriptions" table="category_description">
 <key column="category_id" />
 <map-key-many-to-many column="language_id" class="Language" />
 <element type="string" length="255" column="title" />
</map>

would work just as well.

Note that in both cases your Language class would need to override hashCode() and equals() in order to be able to successfully query the resulting map:

/* eclipse generated */
@Override
public int hashCode() {
 final int prime = 31;
 int result = 1;
 result = prime * result + ((id == null) ? 0 : id.hashCode());
 return result;
}

/* eclipse generated */
@Override
public boolean equals(Object obj) {
 if (this == obj)
  return true;
 if (obj == null)
  return false;
 if (getClass() != obj.getClass())
  return false;
 Language other = (Language) obj;
 if (id == null) {
  if (other.id != null)
   return false;
 } else if (!id.equals(other.id))
  return false;
 return true;
}
Henning
Hi,thanks a lot for the answer. We worked around it in a way I don't like but I will definitely try this out.You're right about the DDL inconsistency; I tried to "simplify" things a bit but obviously missed something.In that respect, the CategoryDescription was simplified as well, it has some more attributes.We have the same 3-table setup for other entities as well (lots of our entities have multilingual descriptions which are designed in a similar way.I'll post back as soon as I find the time to try your solution.Thanks.

related questions