I am using Eclipse to develop Android with Google App engine. I have 3 entities User->UserDetails->UserPassword. Each one has a @OneToOne relationship to the other thru USER_ID. Following are the entities:
@Entity
public class User {
@Id
@Column(name = "USER_ID", allowsNull="false")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key userId;
@Column(name = "USER_NAME", allowsNull="false")
private String userName;
@OneToOne(cascade = CascadeType.ALL,optional=false,orphanRemoval = true)
@JoinColumn(name = "USER_ID")
private UserDetails userDetails;
//getters & setters
}
@Entity(name="USER_DETAILS")
public class UserDetails {
@Id
@Column(name = "USER_ID", allowsNull="false")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key userId;
@Column(name = "USER_FULLNAME", allowsNull="false")
private String userFullname;
@Column(name = "USER_IMAGEURL", allowsNull="false")
private String userImageURL;
@Column(name = "USER_PASSPHRASE", allowsNull="false")
private String userPassPhrase;
@OneToOne(cascade = CascadeType.ALL,optional=false)
@JoinColumn(name = "USER_ID")
private UserPassword userPassword;
//getters & setters
}
@Entity(name = "USER_PASSWORD")
public class UserPassword {
@Id
@Column(name = "USER_ID", allowsNull="false")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key userId;
@Column(name = "USER_PASSWORD", allowsNull="false")
private String userPassword;
//getters & setters
}
I have a removeAllUsers()
method in Userendpoint.java
. This method is suppose to get all the users, iterate thru them and remove users, userDetails and passwords one by one.
public void removeAllUsers() {
log.info("UserEndpoint.removeAllUsers().....");
EntityManager mgr = getEntityManager();
User user = new User();
try {
CollectionResponse<User> allUsers = listUser(null, null);
Collection<User> users = allUsers.getItems();
Iterator<User> itr = users.iterator();
log.info("UserEndpoint.removeAllUsers()....itr.hasNext="+itr.hasNext());
while(itr.hasNext()){
user = itr.next();
user = mgr.find(User.class, user.getUserId());
//mgr.getTransaction().begin();
mgr.remove(user);
//mgr.getTransaction().commit();
log.info("UserEndpoint.removeAllUsers()....User removed");
}
} finally {
mgr.close();
}
log.info("UserEndpoint.removeAllUsers()....End");
}
My assumption is as CascadeType.ALL is used on User, when I delete User, it should remove UserDetails and Password. I also tried with Transaction(lines commented out above). I get the following error:
WARNING: Delete of com.bean.User@15a9289 needs delete of related object at com..bean.User.userDetails but cannot delete it direct since FK is here
Jun 12, 2014 12:04:01 PM com.google.api.server.spi.SystemService invokeServiceMethod
INFO: cause={0}
javax.persistence.PersistenceException: Illegal argument
at org.datanucleus.api.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:298)
at org.datanucleus.api.jpa.JPAEntityManager.close(JPAEntityManager.java:197)`enter code here`
at com.cloudmobilebanking.bean.UserEndpoint.removeAllUsers(UserEndpoint.java:202)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
Also after some lines I see the below comment also:
Caused by: java.lang.IllegalArgumentException: cross-group transaction need to be explicitly specified, see TransactionOptions.Builder.withXGfound both Element {
type: "User"
id: 0x10780000000000
}
and Element {
type: "User"
id: 0x12b80000000000
}
I have tried using TransactionOptions but get the same error.
I also tried deleting Password then userDetails and then User in that seqyence but still same error.
Any ideas how I can resolve this?
After working for sometime with JPA/JDO + google endpoints, I gave up (there were multiple issues). JPA/JDO is more for RDBMS but Google datasore is more like a HashMap. I decided to try Objectify which is designed specifically for Google datastore. My experience with it has been better. You need to read the solution below along with the discussion at: GAE+Objectify - Parameterized type com.googlecode.objectify.Ref not supported to get a better understanding.
In order to delete the User, UserDetails and Password in Objectify, below is the code.
@ApiMethod(name = "deleteAllUsers", path="delete_all_users")