Composition 1:n:1

Full source code is provided in the package: de.laliluna.component.ternary A typical relation for this kind of mapping is: Offer → OfferLine → OfferItem

ClassesTables

images/c_component_collection_ternary_class.jpg

images/c_component_collection_ternary_table.jpg

Of course you could map this without using components as a simple 1:n + 1:1 relation. You may choose the component mapping if your n-class is not an entity that you will deal with directly. Your application logic will probably always access an offerLine by selecting the offer first. In this case you will probably not need an entity offerLine. In case of a relation Customer → Order → Invoice would be probably better mapped as 1:n + 1:1 as you will probably access all three entities. Equals and hashcode As already explained in example component3 you must implement equals and hashcode when you want to use a set. Implementing is not at all easy, so you might consider to prefer list, map, idbag for this kind of mapping. Nevertheless, I used a set here.

Annotation mapping. 

import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.persistence.JoinColumn;
import org.hibernate.annotations.CollectionOfElements;
import javax.persistence.Entity;
...... snip ........

@Entity
@SequenceGenerator(name = "offer_seq", sequenceName = "offer_id_seq")
public class Offer implements Serializable {

   @ElementCollection
   @CollectionTable(name="offer_line", joinColumns = @JoinColumn(name = "offer_id"))
   private Set<OfferLine> offerLines = new HashSet<OfferLine>();

   import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import org.hibernate.annotations.Parent;
@Embeddable  // class can be embedded into other classes
public class OfferLine  implements Serializable{

   @OneToOne  // one to one relation
   @JoinColumn(name="offeritem_id") // optional column name of the foreign key
   private OfferItem offerItem;

   @Parent  // offer is specified as reference back to the embedding class
   private Offer offer;

The OfferLine needs to be embeddable and has a relation to OfferItem. In addition, I added a relation back to the parent class (Offer). OfferItem has no component specific annotations

XML mapping. 

<hibernate-mapping package="de.laliluna.component.ternary " >
  <class name="Offer" table="toffer" >
......... snip .......
    <set name="offerLines" table="toffer_line" >
    <key column="offer_fk" ></key>
      <composite-element class="OfferLine" >
      <parent name="offer"/>
        <property name="quantity" type="integer" ></property>
        <many-to-one name="offerItem" class="OfferItem" >
          <column name="item_fk"></column>
        </many-to-one>
      </composite-element>
    </set>
  </class>
</hibernate-mapping>

OfferItem has no component related tags. It is a simple mapping.

Samples of use:

/* create */
OfferItem item1 = new OfferItem(null, "Red flowers");
session.save(item1);

Offer offer = new Offer();
OfferLine line1 = new OfferLine();
line1.setQuantity(5);
line1.setOfferItem(item1);
offer.getOfferLines().add(line1);
session.save(offer);

/* select offers where quantity of red flowers are 5 */
List<Offer> list = session.createQuery(
   "from Offer o left join o.offerLines l where l.quantity = :q " +
      "and l.offerItem.name = :n")
    .setInteger("q", 5).setString("n", "Red flowers").list();