This discussion is archived
6 Replies Latest reply: Oct 9, 2012 7:48 AM by cdelahun RSS

OneToMany is not working using composite key in JPA2.0 with Ecliselink

948590 Newbie
Currently Being Moderated
Hi,

We are using JPA2.0 with Eclipselink, OneToMany relationship is not working when we are using composite key between two entities. Please find the problem in detail

Class Parent

@EmbeddedId
private ParentPK id;

@OneToMany(cascade = CascadeType.ALL, mappedBy="parents")
@JoinColumns(
{ @JoinColumn(name = "A", referencedColumnName = "A"),
@JoinColumn(name = "B", referencedColumnName = "B")})
private Set<Child> childList;

Class ParentPK

@Column(name = "A", nullable=false)
private String aData;

@Column(name = "B", nullable=false)
private String bData;

Note- parent table primary key is (A, B)


Class Child

@EmbeddedId
private ChildPK id;

@ManyToOne(optional = true)
@JoinColumns(
{ @JoinColumn(name = "A", referencedColumnName = "A", insertable = false, updatable = false),
@JoinColumn(name = "B", referencedColumnName = "B", insertable = false, updatable = false)})
private Parent parents;

Class ChildPK

@Column(name = "A", nullable=false)
private String aData;

@Column(name = "B", nullable=false)
private String bData;

@Column(name = "C", nullable=false)
private String cData;

Note- child table primary key is (A, B, C) and this has refernece to parent table with A, B foreighn key relationship.

I am trying simple entityManager find with Parent class and PArentPK

Parent parent = entityManager.find(Parent.class, parentPK);
System.out.println(" Child list ===> "+ parent.getChildList());

Child list is empty, we are not able to retrieve child list.

I tried all the combinations it is not working, Can some one please suggest us what could be the cause?

Thanks
Chandra
  • 1. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    cdelahun Pro
    Currently Being Moderated
    First thing I noticed is that the OneToMany in parent uses both JoinColumns defined and the mappedBy="parents" designation. These to conflict, and since you have the JoinColumns set in the Child entity, I would remove the joinColumns annotations in the Parent mapping.

    Second, from the sounds of it you are not setting both sides of the relationship. I assume that a Child gets a parent set since its ID is derrived from it, but you haven't mentioned that you also add the Child to the Parent's childList at the same time. If you do not, the cache is inconsistent with what is in the database, resulting in that same Parent object (with the same empty childList) returned when it is next read. JPA does not maintain relationships before you like CMP 2.0 tried to.

    Third, since you are using JPA 2.0, you might want to use the MapsId to manage setting Child's ChildPK's aData and bData fields for you, or remove the embedded ID all together and just have a cData and parents mappings in Child marked with @Id.

    A simple example removing the embedded would be:
    http://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/DerivedIdentifiers

    or with @MapsId and embeddable:
    Class Child 
    
    @EmbeddedId
    private ChildPK id;
    
    @ManyToOne(optional = true)
    @MapsId("parentId")
    private Parent parents;
    Class ChildPK
    
    private ParentPK parentId;
    
    @Column(name = "C", nullable=false)
    private String cData; 
    In these last two senarios, the relationship controls the fields and JPA will set the Child's ID a and b values on persist fom the child's parents relationship for you.

    Best Regards,
    Chris
  • 2. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    948590 Newbie
    Currently Being Moderated
    Hi Chris,

    Thanks for your valuable info and suggestion I have modified my child relation as mentioned below. But still am not able to get child records

    1) I removed two places join relation and mentioned in only parent - Parent relationship as mentioned in first email same no change

    2) I am looking bidirectional, When i get paret need to get childs are associated & when i get child need to get associated parents.

    3) Trying with @mapsId - child relations are modified to


    Class Child

    @EmbeddedId
    private ChildPK id;

    @ManyToOne(optional = true)
    @MapsId("parentPK")     
    private Parent parents;

    @Embeddable
    Class ChildPK

    private ParentPK parentPK;

    @Column(name = "C", nullable=false)
    private String cData;

    Can you please suggest me what is incorrect?
  • 3. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    cdelahun Pro
    Currently Being Moderated
    Hello,

    #1+3 were observations but not really related to the problem. #2 is the most likely cause - when you create the Child and call child.setParents(parent), you must also call parent.getChildList.add(child), and ensure that both are managed for the changes to be reflected in the cache and the database. If you verify that your code is doing this, please show an example of how you are creating and getting the parent and child instances.

    Best Regards,
    Chris
  • 4. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    948590 Newbie
    Currently Being Moderated
    Thanks Chris for helping on this issue

    Mainly am trying with unidirectional first when Parent is retrieved child records should be retrieved. Parent is deleted child records should be deleted.
    As of now assume our requirement is, when I retrieve parent child records has to be retrieved. First an trying with find option whether am able to retrieve, that is failing with composite key.

    I am able to do this with primary key (Non composite key). But not able to do this with composite key as mentioned earlier.

    With out composite key ---- This Read and Delete are working fine. I was just using entitymanager.find() OR named query it works fine.

    public class Stock

    *@Id*
    *@Column(name = "STOCK_ID")*
    private String stockId;

    *@OneToMany(mappedBy = "stock", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY,*
    orphanRemoval = true)
    private Set< Identifier> identifierList;
    ---------------------------
    public class Identifier

    *@EmbeddedId*
    private IdentifierPK id;

    *@ManyToOne*
    *@JoinColumn(name=" STOCK_ID", nullable=false, insertable=false, updatable=false)*
    private Stock stock;

    *@OneToMany(cascade = CascadeType.ALL, mappedBy="identifiers")*
    private Set<Exchange> exchangeList;

    *@Embeddable*
    public class IdentifierPK

    *@Column(name = "A", nullable=false)*
    private String aData;

    *@Column(name = "C", nullable=false)*
    private String cData;

    **** Above relation is fine it is able retrieve identifiers when I retrieve Stock.
    **** Same thing now am trying with Compoite Key entities.

    public class Exchange

    *@EmbeddedId*
    private IdentifierPK id;

    *@ManyToOne(optional = true)*
    *@MapsId("identifierPK")     *
    *@JoinColumns(*
    *{ @JoinColumn(name = "A", referencedColumnName = "A"),*
    *@JoinColumn(name = "B", referencedColumnName = "B")})*
    private Identifier identifiers;

    ----------------------------------------------------------
    *@Embeddable*
    public class ExchangePK

    private IdentifierPK identifierPK;

    *@Column(name = "C", nullable=false)*
    private String cData;

    I am trying with below query only as mentioned earlier. It is not able retrieve
    Identifier identifier = entityManager.find(Identifier.class, identifierPK);
    System.out.println("identifiers list ===> "+ identifier.exchangeList());

    Do let me know your input please
  • 5. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    948590 Newbie
    Currently Being Moderated
    Hi Chirs,

    Adding more info to the problem.

    We are using CHAR(12) for one column(which is primary key) in the database but when we are sending values to that column are CU, IS, SE…etc. When we are executing entitymanager.find() internally oneToMany is executed am able to see the SQL query with values. But I think due to char space issues in JPA oneToMany is not returning result. (empty list is returned)

    Even in our existing queries entitymanager.find() is not working if we pass IS/CU alone we need to append with spaces like *"CU " OR "IS "*..etc. OR we are executing through named query with @hint annotation by turning off bind parameters. For example - *hints = { @QueryHint(name = QueryHints.BIND_PARAMETERS, value = "false") }.* With this hint our named queries are able to retrieve data. But for second level queries seems bind parameter false is not applying.

    Do you think is there any way we can use this bind parameter off for entity manager? OR Is there any way we can set entity manager to ignore spaces for CHAR.

    Let me know your input.

    Thanks
  • 6. Re: OneToMany is not working using composite key in JPA2.0 with Ecliselink
    cdelahun Pro
    Currently Being Moderated
    Hello,

    You can try calling session.getLogin().setShouldTrimStrings(false);
    described here:
    http://wiki.eclipse.org/Configuring_a_Database_Login_(ELUG)#How_to_Configure_Advanced_Options_Using_Java
    in a session customizer described here:
    http://wiki.eclipse.org/Customizing_the_EclipseLink_Application_(ELUG)#Using_the_Session_Customizer_Class

    best regards,
    Chris

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points