0

I have two domain classes. Below is the rough sketch of the classes.

Company.java

public class Company{

    @OneToMany(orphanRemoval="true",cascade=CascadeType.ALL,
    mappedBy="company")
    private List<Department> departments;

}

Department.java

public class Department{

   @ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.PERSIST)
   @JoinColumn(name="company_id")
   private Company company

}

JPA @ManyToOne with CascadeType.ALL says that The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.

Test.java's main method

//session started and transaction begin
Company company=new Company();
company.setName("Company");

Department department=new Department();
department.setName("Testing department");

department.setCompany(company);

session.save(department);

//transaction committed and session closed

It gives my Exception

Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: someValue

But when I use CascadeType.ALL on @ManyToOne annotation,it works fine, but not with CascadeType.PERSIST So what should I use to make this example work without using CascadeType.ALL as ALL uses (PERSIST, REMOVE, REFRESH, MERGE, DETACH). So which of following I should uses to get my work done instead of ALL and how they work?

Community
  • 1
  • 1
Shoaib Chikate
  • 8,665
  • 12
  • 47
  • 70

2 Answers2

1

You have set the CascadeType to PERSIST in Department entity so you have to use session.persist(Object) method instead of save.

So use this:

session.persist(department);

Update:

The Company entity has CascadeType set to ALL on Department. Also in a one-to-many relationship the Many side which is Department is the owner of the association.

So if you save the Company instead of Department the CascadeType.ALL is applicable. As Company is not the owner of the association, you have to add the department to your Company to maintain the bi-directional relationship. The code looks like this.

    List<Department> departments = new ArrayList<Department>();
    departments.add(department);
    company.setDepartments(departments);

    session.persist(company); // or you can also use save here.

If you do not maintain the relationship then Department will not be saved in database.

Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • So my question is how CASCADE.ALL works without using persist method? – Shoaib Chikate Oct 01 '14 at 12:42
  • You have given another option. But save(department) works for CASCADE.ALL and not for CASCADE.PERSIST, this answer is not satisfactory??. In my question I have mention one link which says ALL is combination of MERGE,PERSIST,DETACH,REMOVE etc. Then which options to use instead of ALL as it works with ALL but not with PERSIST. Hope my question is clear. – Shoaib Chikate Oct 01 '14 at 12:54
  • looks like you are confused, `CASCADE.ALL` is provided between Company & Department. So it works for save(company) or persist(company) etc, where as `CASCADE.PERSIST` is provided between`Department` & `Company` so it works only if you do `session.persist(department)`, so what is missing here? it seems you are looking in opposite directions which is not correct. – Chaitanya Oct 01 '14 at 12:57
  • So my question is ALL is present then which cascade types it use. as link says it uses one of the above types. I'm not confuse. Just wanted to know how to use. As ALL internally must be using any of the CASCADE types so what it use. – Shoaib Chikate Oct 01 '14 at 12:59
  • ok, now got your point, `ALL` means all operations, not like any single operation, means not `one of the above types.` . The link in your question tells the same thing --> `The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.` – Chaitanya Oct 01 '14 at 13:02
  • I already said persist & save works in my answer, I clear on what else you are expecting. – Chaitanya Oct 01 '14 at 13:32
  • ok, now I see your updated question. Based on my answer you can already guess what it should be. The answer is PERSIST and SAVE. As you are are using JPA, the answer is `PERSIST` as there is no `SAVE` option. – Chaitanya Oct 01 '14 at 13:34
  • Correct answer is @ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST }) which other person has given. There is no way to change persist() method according to my requirement. Thanks and I will upvote your answer as it could another solution. – Shoaib Chikate Oct 01 '14 at 13:38
  • @ShoaibChikate, first try to understand what each operation will do, then you will know what type to select. `MERGE` is used if you try to load an object from session and at the same time you are creating another object with same id and wanted to merge it with what hibenate is maintaining in session. So unless you do such operation MERGE is not needed. – Chaitanya Oct 01 '14 at 13:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62262/discussion-between-shoaib-chikate-and-chaitanya). – Shoaib Chikate Oct 01 '14 at 13:41
  • `REMOVE`, if you try to delete the child if you want to remove the parent. So based on your requirement you can decide whether you want to have it or not. Same applies to `DETACH` – Chaitanya Oct 01 '14 at 13:41
  • http://chat.stackoverflow.com/rooms/62262/discussion-between-shoaib-chikate-and-chaitanya we can have chat – Shoaib Chikate Oct 01 '14 at 13:42
  • `REFRESH` it has a special meaning, it is not required for you. So based on this explanation you have to decide what is required for your mapping. – Chaitanya Oct 01 '14 at 13:42
  • Sorry please, I cannot join for a chat now. – Chaitanya Oct 01 '14 at 13:43
1

It seems that you are mixing JPA annotations with Hibernate session interface.

If you are using Hibernate Session interface you should youse Hibernate annotations. That is:

  @Cascade(CascadeType.SAVE_OR_UPDATE)
  private Company company

If you choose to use JPA annotations you should use EntityManager interface and call

  entityManager.persist(departement);

instead of session.save().

My suggestion is to stick to the JPA interface and use EntityManager.

UPDATE:

I think the real problem is that you're trying to persist (or save) an unattached entity, the Departement, that is related to another unattached entity, the Company, in a One-to-many relationship. When it happens Hibernate must check if the Company is already present on the db, by merging (attaching) the Company entity. So if you want to insert in the DB a new record for Departement and another one for Company you must alternatively:

  • call persist(company) before saving the departement, so that the Company entity is already merge and Hibernate doesn't need to merge it.

OR add CascadeType.MERGE to Company

@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST })
private Company company
Giovanni
  • 543
  • 2
  • 11
  • So my question is how CASCADE.ALL works without using persist method? – Shoaib Chikate Oct 01 '14 at 12:43
  • you can see whats my actual Question is. ALL means all operations, not like any single operation, means not one of the above types. . The link in my question tells the same thing --> The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities. – Shoaib Chikate Oct 01 '14 at 13:25
  • You need at least @ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST }). CascadeType.ALL includes both – Giovanni Oct 01 '14 at 13:30
  • Please include this in your answer. It works. And no need of calling persist(company). So please update that so I can accept this answer. – Shoaib Chikate Oct 01 '14 at 13:34
  • How MERGE and PERSIST works here in case of two unattached entity? Because I am not calling persist(company) hence Company still in Transient state. – Shoaib Chikate Oct 01 '14 at 13:49
  • yes, and when you call save(departement) (or persist(departement)) the company instance will be merged and thus attached, together with the departement. If a company with the same id already exists in the DB no new records will be created, or else a new record will be inserted. – Giovanni Oct 01 '14 at 14:11