title: Hibernate join mapping for many-to-one with multiple columns
body: <p>I'm trying to use Hibernate to map a table as a set of DTOs into another DTO. I'm running into trouble as I need to do the mapping using two columns. Please could somone tell me what to write in the hibernate mapping file to do the mapping as it seems no matter what I put in the 'join' part of the mapping, it is not accepted as a valid format.</p>
  
  <p>The DTO I'm trying to map with hibernate:</p>
  
  <p>public class CoverageDTO extends BaseDTO {</p>
  
  <pre><code>private SupplierDTO supplierDTO;
  private MarketDTO marketDTO;
  private Float   price;
  private String  currency;
  
  private Set&lt;SpecialRuleDTO&gt; specialRules = new HashSet&lt;SpecialRuleDTO&gt;(0);
  </code></pre>
  
  <p>}</p>
  
  <p>The underlying SQL tables are:</p>
  
  <p>Supplier table, lists which suppliers we have - primary key is SUPPLIER_ID, other details irrelevant.</p>
  
  <p>Market table, lists different markets that suppliers may be able to provide their products in - primary key is MARKET_ID, other details irrelevant.</p>
  
  <p>Coverage table - lists which markets suppliers can reach, and what the price/currency is for that supplier for that market</p>
  
  <pre><code>CREATE TABLE  coverage (
    COVERAGE_ID int(10) unsigned NOT NULL auto_increment,
    SUPPLIER_ID int(10) unsigned NOT NULL,
    MARKET_ID int(10) unsigned NOT NULL,
    PRICE float default NULL,
    CURRENCY varchar(5) default NULL,
    PRIMARY KEY  USING BTREE (COVERAGE_ID)
  ) DEFAULT;
  </code></pre>
  
  <p>supplier_special_rules table - lists the special rules that can be applied to suppliers.</p>
  
  <pre><code>CREATE TABLE  supplier_special_rules (
    SUPPLIER_SPECIAL_RULE_ID bigint(20) unsigned NOT NULL auto_increment,
    SUPPLIER_ID bigint(20) unsigned NOT NULL,
    NAME varchar(128) NOT NULL,
    TYPE varchar(128) NOT NULL,
    VALUE float NOT NULL,
    PRIMARY KEY  (SUPPLIER_SPECIAL_RULE_ID)
  ) DEFAULT;
  </code></pre>
  
  <p>supplier_coverage_special_rules - lists which special rules should be applied for a supplier and for which markets.</p>
  
  <pre><code>CREATE TABLE  supplier_coverage_special_rules (
    SUPPLIER_COVERAGE_SPECIAL_RULE_ID bigint(20) unsigned NOT NULL auto_increment,
    MARKET_ID bigint(20) unsigned NOT NULL,
    SUPPLIER_SPECIAL_RULE_ID bigint(20) unsigned NOT NULL,
    PRIMARY KEY  (SUPPLIER_COVERAGE_SPECIAL_RULE_ID)
  ) DEFAULT;
  </code></pre>
  
  <p>So thinking at an SQL level, I need to map the supplier_special_rules into the coverage table using the information in the supplier_coverage_special_rules table i.e. by matching the MARKET_ID and SUPPLIER_ID columns. I though the mapping below would do it, but it doesn't seem to be a valid mapping syntax.</p>
  
  <pre><code>&lt;hibernate-mapping package="net.dtopath"&gt;
      &lt;class name="CoverageDTO" table="coverage"&gt;
          &lt;id column="COVERAGE_ID" name="ID"&gt;
              &lt;generator class="native"/&gt;
          &lt;/id&gt;
  
          &lt;many-to-one class="net.dtopath.SupplierDTO" column="SUPPLIER_ID" name="supplierDTO"/&gt;
  
          &lt;many-to-one class="net.dtopath.MarketDTO" column="MARKET_ID" name="marketDTO"/&gt;
  
          &lt;property name="price" type="float"&gt;
              &lt;column name="PRICE" not-null="false"/&gt;
          &lt;/property&gt;    
  
          &lt;property name="currency" type="string"&gt;
              &lt;column name="CURRENCY" not-null="false"/&gt;
          &lt;/property&gt;
  
          &lt;!-- Start of the bit that needs editing as it's wrong --&gt;
          &lt;join table="SUPPLIER_COVERAGE_SPECIAL_RULES"&gt;
              &lt;key&gt;
                  &lt;column name="SUPPLIER_ID" not-null="true" /&gt;
                  &lt;column name="MARKET_ID" not-null="true" /&gt;
              &lt;/key&gt;
              &lt;many-to-one name="specialRules" column="SUPPLIER_SPECIAL_RULE_ID" class="SupplierSpecialRuleDTO" not-null="true" /&gt;
          &lt;/join&gt;
          &lt;!-- End of the bit that needs editing as it's wrong --&gt;
      &lt;/class&gt;
  &lt;/hibernate-mapping&gt;
  </code></pre>
  
  <p>Any ideas on how to do this mapping?</p>
  
  <p>(and yes I need to map on supplier_ID and market_ID rather than coverage_ID for various other requirements).</p>
  
  <p><em>EDIT</em></p>
  
  <p>I found elsewhere a suggestion that I should be using properties to define the key that the join should be done on e.g.:</p>
  
  <pre><code>&lt;properties name="keysCoverageSpecialRules"&gt;
      &lt;property name="supplierID" column="SUPPLIER_ID" insert="false" update="false"/&gt;
      &lt;property name="marketID" column="MARKET_ID" insert="false" update="false"/&gt;
  &lt;/properties&gt;
  
  &lt;set name="specialRules" table="SUPPLIER_COVERAGE_SPECIAL_RULES"&gt;
      &lt;key property-ref="keysCoverageSpecialRules"&gt;
      &lt;/key&gt;
      &lt;many-to-many class="SupplierSpecialRuleDTO" unique="true" column="SUPPLIER_SPECIAL_RULE_ID"/&gt;
  &lt;/set&gt;
  </code></pre>
  
  <p>but this give an error "org.hibernate.MappingException: collection foreign key mapping has wrong number of columns: net.dtopath.CoverageDTO.specialRules type: component[supplierID,networkID]"</p>