4

Am new to JPA and I have learned a lot from this forum. I have this problem.

I have 2 tables (Members and Member_next_of_kin). memberId is auto incremental column in members table

The Member_next_of_kin has a referenced column memberId from members tabke which is Mandatory

I have this method to create new member.

public void addMember(Members member) {
    try {          
        createNewMember(member);
        nok.setMemberId(getMemberId());
        addNextOfKin(nok);
    } catch (Exception e) {
        context.setRollbackOnly();
    }
}

public Members createNewMember(Members member) {
    memberFacade.create(member);
    return memberId;
}

My aim is to persist the create Member and return back the created memberId and use it to insert in nextofkin table.

please show me how to do this within the transaction. Memberid is returning null.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Daffyydd
  • 55
  • 3
  • `Memberid is returning null.` indeed, how do you expect it would get any other value? – fvu Oct 30 '15 at 22:40
  • fvu, please let me know how to get the memberId value as part of the transaction before it is commited to table – Daffyydd Oct 30 '15 at 22:43
  • See here http://stackoverflow.com/questions/9732453/jpa-returning-an-auto-generated-id-after-persist , I think that is what you mean. But I suspect you're trying to outsmart JPA, what I think you try to achieve here is typically solved by delegating the work to JPA via @OneToMany relations. Your nextofkin should probably appear as a List in Member, and the handling of the relation should be left to JPA, ie, let it take care of linking up both tables. – fvu Oct 30 '15 at 22:53
  • Dear fvu, you got it right, my nextofkin appears as a collection in member. If i dont pass memberid a value, am getting column constraint error as i have marked it not null. i have tried reading the link above but still am not able to pass the generated id to nextofkin and persist it. how to is this handled by JPA? – Daffyydd Oct 31 '15 at 10:15
  • I would start with a good tutorial about JPA, you could start [here](https://en.wikibooks.org/wiki/Java_Persistence). [This chapter](https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing) talks about id columns an autogeneration, and [here](https://en.wikibooks.org/wiki/Java_Persistence/Relationships) you can read about the different types of relationships JPA can handle. JPA is **not** a less wordy "alternative" to JDBC, it's an entirely different concept. – fvu Oct 31 '15 at 11:50
  • This is not JSF. So I removed the JSF tag and fixed the incorrect term in the question. To learn what exactly JSF is, head to http://stackoverflow.com/tags/jsf/info – BalusC Oct 31 '15 at 18:15

1 Answers1

2

In JPA you would model the required behavior with a relationship - in your case @OneToMany instead of a plain reference to the identifier of the other entity.

JPA is an object-relational mapping, so think in terms of OO design. Now lets try to model this as simply as possible based on the information you provided:

@Entity
public class Member {
@Id
@GeneratedValue
private Long id;

@OneToMany(mappedBy="member")
private Set<NextOfKin> kindred;
}

and

@Entity
public class NextOfKin {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    private Member member;
    }

Now this is where some of JPA complexity comes to place, and it is for the best if you first try to get a basic grasp of some of the important concepts in JPA.

What we have modeled here is a bidirectional one-to-many/many-to-one relationship in JPA terms. In SQL, the NextOfKin table will get a foreign key poiting to Member table. Every bidirectional relationship has one owning side and one inverse side. Owning side may or may not correspond to the natural relationship between the two entities. In JPA, owner is the entity, that is responsible for management of the relationship(foreign keys) in the database. According to JPA spec, in case of bidirectional one-to-many relation, the Many side should always be the owning side- in your case the NextOfKin. We designate the inverse side by using mappedBy attribute of @OneToMany Only by performing DB operations on the owner can you correctly manage the relationship in DB. There are multiple ways how to achieve the functionality you require:

Lets say you start with an empty DB, no Members and no NextOfKins. Your example could be implemented like this.

Member newMember = new Member();
NextOfKin nok = new NextOfKin();
createNewMember(newMember);//here something like em.persist() should happen
//after the save, the member.getId() will return a generated Long identifier 
//because we annotated the id attribute with @GeneratedValue
//NextOfkin is the owner, therefore we need a correct in 
memory relationship    from its point of view 
nok.setMember(newMember);
createNewNok(nok);//again persist the entity
//end of transaction

After this, the relationship in DB should be correct - the NextOfKin table has one entry, with generated Long Id and a FK pointing to the entry in Member table. The information in the DB is correct, even though in Java, Member did not have any elements in its kindred collection. You can verify it by loading the member from DB e.g.

Member fromDB = entityManager.find(Member.class, newMember.getId());
assertTrue("Member should have exactly one next of kin now", 
    fromDB.getKindred().size() == 1);
//and also from the other side
NextOfKin nokFromDB = entityManager.find(NextOfKin.class, nok.getId());
assertTrue("next of kin should have a member", 
    nokFromDB.getMember().getId() == newMember.getId())

There are other options, for example, you could add a Cascade behaviour to the relationship, so that a DB operation performed on Member would be cascaded to kindred:

//...in Member
@OneToMany(cascade=CascadeType.ALL, mappedBy="member")
//... saving member will now save NextOfKin as well,
//but remember, we have to set the correct information in memory
// from the point of view of the owner
Member newMember = new Member();
NextOfKin nok = new NextOfKin();
nok.setMember(newMember);
createNewMember(newMember);

Another option is to make the relationship unidirectional - so that the NextOfkin would not have a relation to Member. Therefore all operations would be performed on the Member table.

For more information on JPA owning/inverse side have a look at some popular questions here at SO , e.g. In a bidirectional JPA OneToMany/ManyToOne association, what is meant by “the inverse side of the association”?

JPA and ORM in general is a complex subject, and I highly recommend spending some time with the documentation or a good book. The minimum knowledge that is, in my opinion, required to productively use JPA is basic Entity mapping, relationship mappings, fetching strategies, understanding of owner/inverse concept and cascading.

You can find many sources online and for free, with varying levels of complexity.
Some useful resources:

Good luck and do not forget, there is always more than one of how to achieve your goals. If you find JPA too complex, you can try some other Java DB frameworks like jOOQ or mybatis.

Community
  • 1
  • 1
yntelectual
  • 3,028
  • 18
  • 24
  • Great...! You are a genius , I became fond of your step by step instructions to solve desired problem. wishing to see more great stuff by you in this community. :). – Arshad Ali Nov 06 '15 at 15:17