views:

62

answers:

1

i've three entity classes in my project

public class Blobx {
@ManyToOne
private Userx user;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
}

public class Index  {
@Id
private String keyword;
@OneToMany(cascade = CascadeType.PERSIST)
private List<Blobx> blobs;
}

public class Userx  {
@Id
private String name;  
@OneToMany(mappedBy = "user")
private List<Blobx>blobs;
}

while running the following lines app engine throws an exception

    em.getTransaction().begin();
    em.persist(index);
    em.getTransaction().commit();//exception is thrown
    em.close();

as

Caused by: java.lang.IllegalArgumentException: can't operate on multiple entity groups in a single transaction. found both Element 


{
    type: "Index"
   name: "function"
  }
  and Element {
    type: "Userx"
    name: "18580476422013912411"
  }

i can't understand what's wrong?

+1  A: 

What's happening (based on the error message) is that you're trying to persist the Index, which contains Blobxes, which contain Userxes, which are all in different entity groups, in a transaction. When you call em.persist(index), it will cascade persist all the entities inside it, and all those inside them.

Think of an entity group as a cluster of machines. Some of your Indexes are on Cluster A, in Nevada. The Blobxes contained within are on Cluster B, in Maine, and the Userxes contained in there are in Clusters B and C, in Texas and Oregon. How they all ended up there is entirely random, and (with your code as it is) entirely out of your control. Asking App Engine to persist all of these geographically disparate entities and know when one fails (i.e., in a transaction) is nearly impossible, and would require a ton of network cross-talk to have all parties know that all other parties are doing okay. So it's not allowed.

What you want to do is make sure Google puts all your entities in one Entity Group, which will mean that they're all in one (geographical) place. To do that, read the docs for Transactions, which describe how to make sure your entities end up in the same entity group, which means they'll be able to have a transaction worked on all of them.

Now, entity-grouping things has its downsides. Namely slowness, and uneven utilization of the datastore (e.g., now that all your entities will be in Texas, users in Oregon will see unnecessary slowness!), so only use entity groups if you absolutely need to use transactions on all entities. For example, don't use a cascading persist unless you actually have to, or don't do it in a transaction unless you actually have to.

Jason Hall