Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Problems with EclipseLink when Composite Primary Key is involved

Hello friends,

I have 1 Profile and * ProfileItem.

1 Profile --- * ProfileItems  ( One profile can have Many ProfileItems).

Note : 1. Its a one-to-many relationship from profile to profileItem.
          2. Its a unidirectional relationship.

PK for Profile is profile_id.

PK for ProfileItem is a composite primary key ( profile_id, from_id )

Firstly, I would I like to complain that EclipseLink doesnt work like Hibernate :

1st Problem with EclipseLink:
Just becasue I have a composite primary key in child entity called ProfileItem, its forcing me to use JoinColumns. I cant use  @JoinColumns as other column from_id is not a foreign key to any other table.
I initially used same annotation which worked perfectly with hibernate as follows :

@Entity
@Table(name="profile_table")
class Profile {

    @Id
    @Column(name="profile_id")
    private Integer profileId ;
     ...

    /**
     *  WORKS WITH HIBERNATE AS PERSISTENCE PROVIDER, BUT FAILS WITH ECLIPSELINK
    */
    @OneToMany( cascade = CascadeType.ALL )
    @JoinColumn( name= "profile_id", referencedColumnName="profile_id" )
    private Set<XVMUpdateProfileItem> profileItems = null;
    
    ...
}




Above code throws following error with eclipselink :

The @JoinColumns on the annotated element [field profileItems] from the entity class [class arun.ucerelay.datastructures.XVMUpdateProfile] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.

Some how I managed to get this working for loading profiles and related profile items.
THIS DOESNT MAKE ANY SENSE TO DECLARE SAME @JoinColumn AGAIN...BUTS FUNNILY WORKS WITH ECLIPSELINK
. This is a bug.

    /**
     *  WORKS WITH ECLIPSELINK AS PERSISTENCE PROVIDER
     */
    
    @OneToMany( cascade = CascadeType.ALL)
    @JoinColumns({
        @JoinColumn( name= "profile_id", referencedColumnName="profile_id" , insertable = true, updatable = true),
        @JoinColumn( name= "profile_id", referencedColumnName="profile_id" , nullable = false)    
    })
    private Set<XVMUpdateProfileItem> profileItems = null;

   
If any one can tell me any right way of implementing unidirectional relationship, please tell me.

2nd Problem with EclipseLink:

Now that I managed to get loading working, I tried my hands at saving profile and cascading the save operation for related child ProfileItem entities.

With Hibernate, this is how I coded which worked perfectly fine :

@Entity
@Table(name="profile_table")
public class XVMUpdateProfile implements Serializable {

   
    @Id
    @Column(name="profile_id")
    @TableGenerator(name = "UCERELAY_TABLE_GENERATOR",
                    table= "SEQUENCE",
                    pkColumnName="SEQ_NAME",
                    valueColumnName ="SEQ_COUNT",
                    pkColumnValue="PROFILE_SEQ",
                    initialValue = 30,
                    allocationSize = 10)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "UCERELAY_TABLE_GENERATOR")
    private Integer profileId ;

    ...

    /**
     *  WORKS WITH HIBERNATE AS PERSISTENCE PROVIDER
    */
    @OneToMany( cascade = CascadeType.ALL )
    @JoinColumn( name= "profile_id", referencedColumnName="profile_id" )
    private Set<XVMUpdateProfileItem> profileItems = null;

   ...
}

@Entity
@Table(name="profile_basket_
table")
public class XVMUpdateProfileItem implements Serializable, Comparable<XVMUpdateProfileItem> {
  
    private static Log logger = LogFactory.getLog(XVMUpdateProfileItem.class);
    private static final long serialVersionUID = 1L;
   
    @EmbeddedId
    private XVMUpdateProfileItemPK key;
   
    ...
}

@Embeddable
public class XVMUpdateProfileItemPK implements Serializable, Comparable<XVMUpdateProfileItemPK>  {
  
    private static final long serialVersionUID = 1L;
   
    @Column(name="profile_id", nullable=false)
    private int keyId = 1;  // assigned a default value.
   
    @Column(name="from_node", nullable=false)
    private int fromNode = -2;
   
}


-- Main Program ---
public class UpdateProfileSave3 {
     
    private static Log logger = LogFactory.getLog(UpdateProfileMain.class);
    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("usinghibernate");
     public static void main(String args[]) {
        List<XVMUpdateProfile> profiles = new ArrayList<XVMUpdateProfile>();
        try {
            // First unit of work
            EntityManager em = emf.createEntityManager();
           
               EntityTransaction etx = em.getTransaction();
            etx.begin();
           
            XVMUpdateProfile profile = "" XVMUpdateProfile();
            profile.setCreatorId(90);
            profile.setProfileDescription("Newly created to check generation of id");
            profile.setProfileName("Mahesh Babu Profile");
           
            Set<XVMUpdateProfileItem> items = profile.getProfileItems();
           
            XVMUpdateProfileItem newItem = new XVMUpdateProfileItem();
            newItem.setAction(XVMUpdateAction.ITEM_INSTALL);
            newItem.getKey().setFromNode(90);
           
            items.add(newItem);
            profile.setProfileItems(items);
            em.persist(profile);
            etx.commit();
            em.close();
        }catch(Exception ex){
            logger.debug(" Arun Could not load profiles : " + ex.getMessage());
            ex.printStackTrace();
        }           
}


}

----------------------------
I created one parent entity ( profile ) and attached one child entity ( profile_item ) and saved the parent entity ( profile ). I expected it to insert one profile and one profile_item with correct profile_id.

As expected it did that with 3 DML statements :

insert into profile_table (creator_manager_id, lastupdate, description, profile_name, creatorname, profile_id) values (90, '2011-04-01 15:23:48', 'Newly created to check generation of id', 'Mahesh Babu Profile', 'Unspecified', 1130);

insert into profile_basket_table (action, from_node, profile_id) values (9, 90, 1)

update profile_basket_table set profile_id=1130 where from_node=90 and profile_id=1

DB results :

select PROFILE_ID, CREATOR_MANAGER_ID from profile_table where profile_id = 1130;

PROFILE_ID     CREATOR_MANAGER_ID    
---------------------- ----------------------
1130                   90                    


select * from profile_basket_table where profile_id = 1130;

FROM_NODE  PROFILE_ID     ACTION                
---------------------- ---------------------- ----------------------
90                     1130                   4                     

It inserted parent and child as expected.


Now it eclipse link, after fixing the issue mentioned in Problem 1 above,

I tried to execute the same problem, with fix to a single line :

   private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("usingeclipselink");

It also issues 3 statements. But last update statement was erroneous.

INSERT INTO profile_table (profile_id, lastupdate, creator_manager_id, description, creatorname, profile_name) VALUES (?, ?, ?, ?, ?, ?)
    bind => [115, 2011-04-01 15:37:13.257, 90, Newly created to check generation of id, Unspecified, Mahesh Babu Profile]

INSERT INTO profile_basket_table (action, from_node, profile_id) VALUES (?, ?, ?)
    bind => [4, 90, 1]

UPDATE profile_basket_table SET profile_id = ? WHERE ((profile_id = ?) AND (from_node = ?))
    bind => [
1, 1, 90] 

Can someone address the problems I mentioned in above mail ?
Are those known bugs with eclipselink ?

--
Thanks,
Arun Kandregula.

Back to the top