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.
|