Question

I'm using Hibernate 4. I have this database with Category and CategoryItem tables:

CREATE  TABLE `test`.`Category` (
  `Id` INT NOT NULL AUTO_INCREMENT ,
  `Description` VARCHAR(50) NOT NULL ,
  PRIMARY KEY (`Id`) )

CREATE  TABLE `test`.`CategoryItem` (
  `IdCategory` INT NOT NULL ,
  `Id` VARCHAR(10) NOT NULL ,
  `Description` VARCHAR(100) NOT NULL ,
  PRIMARY KEY (`Id`, `IdCategory`) ,
  CONSTRAINT `fk_table1_Category1`
    FOREIGN KEY (`IdCategory` )
    REFERENCES `test`.`Category` (`Id` ))

This are used to store different categories or catalogs and its values. For example:

Category table:

1, 'Genders'
2, 'Marital status'
3, 'Countries'

CategoryItem table:

1, 'FEM', 'Female'
1, 'MAL', 'Male'
2, 'SIN', 'Single'
2, 'MAR', 'Married'
3, 'US', 'United States'
3, 'UK', 'England'

These values are used all over the schema, but with logical reference to CategoryItem(Id) only, for example:

CREATE  TABLE `test`.`Person` (
  `Id` INT NOT NULL ,
  `Name` VARCHAR(30) NULL ,
  --this fields are referencing CategoryItem(Id)
  `IdGender` VARCHAR(10) NOT NULL ,
  `IdMaritalStatus` VARCHAR(10) NOT NULL ,
  `IdCountryOrigen` VARCHAR(10) NOT NULL ,
  PRIMARY KEY (`Id`) )

Is it possible to map this tables with some technique in Hibernate? I'm not able to change this schema right now.

EDITED:

These are the classes and mappings so far:

public class Category implements Serializable {

    private int id;
    private String description;

    private Set<CategoryItem> items = new HashSet<CategoryItem>();

    public Category() {
    }

    //getters and setters omitted
}

public class CategoryItem implements Serializable {

    private CategoryItemId id;
    private Category category;
    private String description;

    public CategoryItem() {
    }
    //getters and setters omitted
}

public class CategoryItemId implements Serializable {

    private Category category;
    private String id;

    public CategoryItemId() {
    }
    //getters and setters omitted
}

public class Person implements Serializable {

    private int id;
    private String name;
    private CategoryItem gender;
    private CategoryItem maritalStatus;
    private CategoryItem countryOrigen;

    public PersonaNatural() {
    }
    //getters and setters omitted
}

  <class catalog="test" name="test.Category" table="Category">
    <id name="id" type="int">
      <column name="Id"/>
      <generator class="increment"/>
    </id>
    <property name="description" type="string">
      <column length="50" name="Description" not-null="true"/>
    </property>
    <set inverse="true" name="items">
      <key>
        <column name="IdCategory" not-null="true"/>
      </key>
      <one-to-many class="test.CategoryItem"/>
    </set>    
  </class>

  <class catalog="test" name="test.CategoryItem" table="CategoryItem">
    <composite-id class="test.CategoryItemId" name="id">
        <key-many-to-one name="category" class="test.Category">
            <column name="IdCategory" not-null="true"/>
        </key-many-to-one>
      <key-property name="id" type="string">
        <column name="Id"/>
      </key-property>
    </composite-id>
    <many-to-one name="category" class="test.Category" fetch="select" insert="false" update="false">
      <column name="IdCategory" not-null="true"/>
    </many-to-one>
    <property name="description" type="string">
      <column name="Description" length="100" not-null="true"/>
    </property>
  </class>

<class catalog="test" name="test.Person" table="Person">
    <id name="id" type="int">
      <column name="Id"/>
      <generator class="increment"/>
    </id>
    <property name="name" type="string">
      <column length="30" name="Name" not-null="false"/>
    </property>
    <many-to-one name="gender" class="test.CategoryItem" fetch="select">
        <column name="IdGender" not-null="true"/>
    </many-to-one>
    <many-to-one name="maritalStatus" class="test.CategoryItem" fetch="select">
        <column name="IdMaritalStatus" not-null="true"/>
    </many-to-one>
    <many-to-one name="countryOrigen" class="test.CategoryItem" fetch="select">
        <column name="IdCountryOrigen" not-null="true"/>
    </many-to-one>
  </class>

I'm trying with many-to-one but I'm getting this error: 'must have same number of columns as the referenced primary key'. This makes sense because I'm pretending to map just CategoryId(Id) on Person.hbm.xml.

I'm gonna need to specific a where or discriminator value to complete the left join condition, because CategoryItem(Id) alone is not unique.

Maybe this is not even possible with Hibernate, but any help I will appreciate. Thanks.

Was it helpful?

Solution

This is how I solve the Person mapping:

<class catalog="test" name="test.Person" table="Person">
    <id name="id" type="int">
      <column name="Id"/>
      <generator class="increment"/>
    </id>
    <property name="name" type="string">
      <column length="30" name="Name" not-null="false"/>
    </property>
    <many-to-one name="gender" class="test.CategoryItem" fetch="select">
        <formula>1</formula>
        <column name="IdGender" not-null="true"/>
    </many-to-one>
    <many-to-one name="maritalStatus" class="test.CategoryItem" fetch="select">
        <formula>2</formula>
        <column name="IdMaritalStatus" not-null="true"/>
    </many-to-one>
    <many-to-one name="countryOrigen" class="test.CategoryItem" fetch="select">
        <formula>3</formula>
        <column name="IdCountryOrigen" not-null="true"/>
    </many-to-one>
  </class>

Adding the <formula>(IdCategory)</formula> instead of <column> element causes hibernate matches the composite Id of CategoryItem and resolve correctly the left join.

Thanks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top