Hello,
I have a problem with automatic deleting of opposite references in emf model loaded with teneo if SET_PROXY (enable using of hibernate proxies for ONE-TO-ONE and ONE-TO-MANY references) option enabled. Looks like it is bug in teneo. It would be great if someone can comment it or have experience in using of hibernate proxies with teneo.
I have the following model:
Entity "User":
public interface User extends SomeBase {
EList<Role> getRoles();
[some additional properties]
}
Entity "Role":
public interface Role extends SomeBase {
EList<User> getUsers();
[some additional properties]
}
So entity "User" has non-containment reference to "Role", and "Role" has opposite non-containment reference to "User".
I use Teneo to map my model to database with Hibernate. Model in run-time contains one User object (user1) and one Role object (role1). This entities refer to each other. Both entities was load from database and are managed.
I perform the following operation:
user1.getRoles().clear();
The type of "roles" list is "HibernatePersistableEList". Method clear performs removing of elements (role1) from "roles" list and them for each role performs removing of user1 from opposite reference.
So after this operation user1 doesn't refer to role1 and role1 doesn't refer to user1.
This works fine as long as I did not start the using of hibernate proxy objects by enabling PersistenceOptions.SET_PROXY. In this case entities are javassist or cglib proxies, list also stored references to proxies.
I looked through code and found broken place: call of inverseRemove method in org.eclipse.emf.ecore.util.DelegatingEcoreEList<E> (base class for HibernatePersistableEList)
@Override
public NotificationChain inverseRemove(E object, NotificationChain notifications)
{
InternalEObject internalEObject = (InternalEObject) object;
if (hasNavigableInverse())
{
if (!hasInstanceClass())
{
return
internalEObject.eInverseRemove
(owner,
internalEObject.eClass().getFeatureID(getInverseEReference()),
null,
notifications);
}
else
{
return
internalEObject.eInverseRemove
(owner,
getInverseFeatureID(),
getInverseFeatureClass(),
notifications);
}
}
else
{
return
internalEObject.eInverseRemove
(owner,
InternalEObject.EOPPOSITE_FEATURE_BASE - getFeatureID(),
null,
notifications);
}
}
Last call is:
return
internalEObject.eInverseRemove
(owner,
getInverseFeatureID(),
getInverseFeatureClass(),
notifications);
It is call of generated eInverseRemove method in Role entity. Please note that "owner" attribute of HibernatePersistableEList alwas stores unwrapped entity (not proxy). But we have the following generated code in RoleImpl->eInverseRemove:
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID) {
case AccesscontrolPackage.ROLE__ROLE_PERMISSIONS:
return ((InternalEList<?>)getRolePermissions()).basicRemove(otherEnd, msgs);
case AccesscontrolPackage.ROLE__USERS:
return ((InternalEList<?>)getUsers()).basicRemove(otherEnd, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
getUsers() call returns the list of proxies, but we try to remove unwrapped (not proxy) object from this list. And as result there is no any modifications in users list and role1 stores the reference to the user1 as before.
So i tried it with teneo version 1.2 and 2.0, hibernate 3.6 and 4.1 with last possible emf version and result is the same. Also i tried different proxies type (javassist and cglib fro hibernate 3.6). Also i have the same behavior if i enable PersistenceOptions.FORCE_LAZY option.
Thanks,
Vyacheslav
[Updated on: Mon, 03 September 2012 03:04]
Report message to a moderator