Wednesday, November 25, 2009

How to use Hibernate @Any annotations?

For example let's assume three different applications which manage a media library - the first application manages books borrowing, the second one DVDs, and the third VHSs. The applications have nothing in common. Now we want to develop a new application that manages all three media types and reuses the exiting Book, DVD, and VHS entities. Since Book, DVD, and VHS classes came from different applications they don't have any ancestor entity - the common ancestor is java.lang.Object. Still we would like to have one Borrow entity which can refer to any of the possible media type.
To solve this type of references we can use the any mapping. this mapping always includes more than one column: one column includes the type of the entity the current mapped property refers to and the other includes the identity of the entity, for example if we refer to a book it the first column will include a marker for the Book entity type and the second one will include the id of the specific book.
@Entity
@Table(name = "BORROW")
public class Borrow{

@Id
@GeneratedValue
private Long id;

@Any(metaColumn = @Column(name = "ITEM_TYPE"))
@AnyMetaDef(idType = "long", metaType = "string",
metaValues = {
@MetaValue(targetEntity = Book.class, value = "B"),
@MetaValue(targetEntity = VHS.class, value = "V"),
@MetaValue(targetEntity = DVD.class, value = "D")
})
@JoinColumn(name="ITEM_ID")
private Object item;

.......
public Object getItem() {
return item;
}

public void setItem(Object item) {
this.item = item;
}

}

6 comments:

  1. what are the fields of the borrow method..?
    one is
    borrow table
    has id field,
    what will be item datatype (long Or...) in the actual db
    what is ITEM_TYPE and ITEM_ID in the above example

    if possible please show the borow.hbm.xml
    and the actual db definition of the borrow table
    to see the fields and their data types.

    ReplyDelete
  2. @komal

    There is no borrow.hbm.xml for this. this works with Annotaion
    To simplyfy this more u can try this

    @Any(metaColumn = @Column(name = "service"))
    @AnyMetaDef(idType = "long", metaType = "string", metaValues = {
    @MetaValue(value = "SERVICE", targetEntity = Service.class),
    @MetaValue(value = "SERVICE1", targetEntity = Service1.class),
    @MetaValue(value = "SERVICE2", targetEntity = Service2.class)
    })
    @JoinColumn(name = "service_id")
    @Cascade(value = org.hibernate.annotations.CascadeType.ALL)
    private Service service;

    service and service_id will be autogenrated to keep refrance to the sub classes

    ReplyDelete
  3. @Jason,

    Thanks Jason I was able to get the sample working :) as the borrow.hbm.xml would not exist I used the the AnnotationConfiguration to buildFactory instead of the Configuration that I was using..

    I am also having questions regarding fetching the
    referenced sub class object based on some constraints like
    1) what should I do if I want to list only service class objects?

    2) Also is it possible to to do listing with constraints on the service object?
    eg: If I need the service objects whose name property or field starts with 'A'..
    I need to do this listing through borrow table..


    3) Is search applicable on the any object?

    4)Is service_id and service accessible to us for reuse or manipulation?


    please let me know if the above questions are valid and applicable...

    thanks,
    Komal

    ReplyDelete
  4. @Komal

    Yes, you can search for sub classes or for a property simplify by adding a hibernate Criteria
    Something like this

    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ApplicationImpl.class);
    criteria.add(Restrictions.sqlRestriction("service = 'SERVICE1'"));
    criteria.add(Restrictions.sqlRestriction("status_id = 1"));

    use criteria.list() to return the list

    service_id is accessible and the object that are referenced can be change.

    ReplyDelete
  5. Hi,
    I have three parents tables menu,service,text and one child table named defination_mapping now i want to use @Any to store the parent_type and id in defination_mapping table when tried using the above the values of parent_type and id are stored as null can some one help

    ReplyDelete
  6. can we use same target entity for multiple values in @Any annotation
    e.g: @MetaValue(value = "A", targetEntity = Type.class),
    @MetaValue(value = "B", targetEntity = Type.class),
    @MetaValue(value = "C", targetEntity = Type.class)

    ReplyDelete