0

In my database table Attribute, I will have a list of data loaded first. Every time, when I want to persist a new record of MyAttribute, I will need to search through the table Attribute first and select the appropriate record from table Attribute before I insert to table MyAttribute.

@Entity
class MyAttribute{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @ManyToOne(targetEntity = Attribute.class)
    @JoinColumn(name="attribute_id", referencedColumnName="id")
    Attribute detail;

    private String greet;

    public MyAttribute(){
        this.greet = "Hello World.";
        this.detail = new MyDbLayer().selectAttributeDetail("first"); //Error is thrown here.
    }

    //getter & setter
}

@Entity
class Attribute{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Index(name = "name_index")
    @Column(unique=true )
    private String name;

    //getter & setter
}

class MyDbLayer{
    private EntityManagerFactory emf;

    public MyDbLayer() {
        emf = Persistence.createEntityManagerFactory("MyPu");
    }

    public Attribute selectAttributeDetail(String name) {
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

        Query queryGetAttribute = em.createQuery("select a from Attribute a where a.name = :attributeName");

        List<AttributeDescription> attributeDescList = queryGetAttribute.setParameter("attributeName", name).getResultList();

        AttributeDescription tempAttribute = null;

        if (!attributeDescList.isEmpty()) {
            tempAttribute = (AttributeDescription) attributeDescList.get(0);
        }

        em.clear();
        em.close();

        return tempAttribute;
    }
}

I'm not sure why I keep on receiving error like:

javax.persistence.PersistenceException: [PersistenceUnit: MyPu] Unable to build EntityManagerFactory

Caused by: org.hibernate.MappingException: Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister

Caused by: org.hibernate.InstantiationException: could not instantiate test object

P.S. This is not the real code that I'm working on, but the structure is more or less the same.

Ryu
  • 103
  • 3

2 Answers2

3

What about making a second construtor for MyAttribute?

public MyAttribute(){
    this.greet = "Hello World.";
    // this.detail = new MyDbLayer().selectAttributeDetail("first"); //Error is thrown here.
}

public MyAttribute(Attribute detail){
    this.greet = "Hello World.";
    this.detail = detail;
}

The default constructor is also used by jpa to load persited objects. this can cause unexpected behaviour

Hank Lapidez
  • 1,857
  • 18
  • 23
  • JPA *needs* a no-args constructor to work, see http://stackoverflow.com/questions/2808747/why-does-jpa-require-a-no-arg-constructor-for-domain-objects – Tassos Bassoukos Jul 09 '14 at 10:44
  • But in this case, will I not rewrite a lot of the code that call MyAttribute? What if I want to reduce rewriting it in all different class that call the constructor? – Ryu Jul 10 '14 at 02:06
  • Well I think you must find path of least resistance. Perhaps make a factory that builds the initialised Object for you and then search and replace 'new MyAttribute()' with the factory call – Hank Lapidez Jul 10 '14 at 09:25
0

It is not in the JPA model to be able to access an EntityManager from an Entity. It can be done, but it can have different behaviors depending on the implementation.

In your case accessing an EntityManager from the no args constructor is never a good idea. Because thats the constructor used by the EntityManager when it loads an Entity. So every time MyAttribute is loaded by an EntityManager you will try to create antoher EntityManager to initialise the detail relationship which will be overwritten by the first EntityManager using the value it loaded from the database.

Usually you should have a service layer which has access to an EntityManager that manages your JPA Entities.

user3679868
  • 693
  • 4
  • 6