0

I am working on achieving composition in hibernate through the use of components (Embeddables in JPA terminology). I am using simple example of User and Address. While using Hibernate 5.2, whenever I am trying to create an @Id in @Embeddable class, hibernate is throwing Assertion Failure

Declaring class is not found in the inheritance state hierarchy

If I remove the @Id annotation and set its value through setter method, both the tables are getting populated correctly.

As per general database rules, every table must have a primary key, even if there exist a referential relationship between some columns of two or more tables. I know that a primary key can be created on the join table for an @ElementCollection through

@GenericGenerator(name="sequence-gen",strategy="sequence")
@CollectionId(columns = { @Column(name="JOIN_TB_PRI_KEY") }, generator = "sequence-gen", type = @Type(type="long"))

What I am confused about is why cannot I just use an @Id in the Address class.

UserDetails Class

@Entity
@Table(name = "USER_DETAILS")    
public class UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int userId;
    private String userName;

    @ElementCollection
    @JoinTable(name = "USER_ADDRESS", joinColumns = @JoinColumn(name = "REFERRED_USER_ID"))
    private Collection<Address> listOfAddress = new ArrayList<>(); 

    // accessor and mutator methods
}

Address Class

@Embeddable
public class Address {

    @Id // throws Assertion Failure while using it, else runs correctly
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int addressPrimaryKey;

    @Column(name = "STREET_NAME")
    private String street;
    @Column(name = "CITY_NAME")
    private String city;
    @Column(name = "STATE_NAME")
    private String state;
    @Column(name = "ZIP")
    private String pinCode;

    // accessor and mutator methods
}

HibernateUtil Class

public class HibernateUtil {

    public static void main(String[] args) {

        Address addr1 = new Address();
        addr1.setStreet("Street 1");
        addr1.setCity("City 1");
        addr1.setState("State 1");
        addr1.setPinCode("Zip 1");
        addr1.setAddressPrimaryKey(100);     // this value should be auto generated

        Address addr2 = new Address();
        addr2.setStreet("Street 2");
        addr2.setCity("City 2");
        addr2.setState("State 2");
        addr2.setPinCode("Zip 2");
        addr2.setAddressPrimaryKey(200);    // this value should be auto generated


        UserDetails user1 = new UserDetails();
        user1.setUserName("First User");
        user1.getListOfAddress().add(addr1);
        user1.getListOfAddress().add(addr2);

        UserDetails user2 = new UserDetails();
        user2.setUserName("Second User");

        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            session.save(user1);
            session.save(user2);
            tx.commit();
        }

        catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
            throw e;
        }

        finally {
            session.close();
        }
    }

}
sss
  • 598
  • 6
  • 24
  • By definition, an embeddable doesn't have an ID, since it's used as part of the state of another entity, which is the one having an ID. Using `@Id` in an Embeddable makes no sense. If an address has its own ID and must be saved in its own table, then is must be an entity, and the collection of addresses is not an ElementCollection, but a OneToMany. – JB Nizet Mar 13 '18 at 07:56
  • @JBNizet This comment has me more confused. If ElementCollection is part of the parent class, why is it getting saved in a separate table. Isn't it violating ER Modelling principles? – sss Mar 13 '18 at 08:07
  • Because there is no way to save many addresses in a single table. – JB Nizet Mar 13 '18 at 09:06

1 Answers1

0

@ElementCollection is collection of elements. It can be collection of primitive types or @Embeddable elements (sub entities). So this means that this sub entities are part of main entity and don't have their own life cycle. And as a result they don't have their own id @Id.

In case if you need to provide it's own primary Id then the correct approach would be to create two tables UserDetails and Address. Then create two entity classes @Entity and @OneToMany or @ManyToOne relationship (depends on your business case).

Mara
  • 2,947
  • 2
  • 12
  • 17