How to ensure unmanaged/managed object identity in OpenJPA?
I am using OpenJPA to persist objects. I was originally using OpenJPA 1.2 but then upgraded to OpenJPA 2.1. Objects are kept on the server in memory and they are serialized to the client and may be received back as unamanged. Dozer is used to remove the JPA stuff and always has. It has not caused any problems before. I depend on JPA being able to recognise the @Id when saving an dozer mapped JPA object.
So essentially I have a large nested graph of objects, some with bidirectional (cylical) references. This structure has data that is changed and data that is not changed by the client. It's sent to the client, it may or may have not been persisted before. It only gets persisted when it is sent back to the server at least once. I have an object that refers to another object in a OneToOne relationship:
class A {
@Column("b_id")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
@OneToOne
@JoinColumn(name="b_id")
B something
@OneToOne
Graph owner;
}
class B {
@Column("b_id")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
}
class Graph {
@Column("graph_id")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
@OneToOne
@Column
A item;
}
The problem is that when I receive the object back*, it's of a different instance of the one stored on the server and it's unmanaged. If I add cascade = CascadeStrategy.ALL I get duplicate inserts as it adds the object to the database again. If I leave it off, I get an exception that JPA tried to persist an unmanaged object, please add an annotation. In summary:
Graph is n开发者_开发技巧ot persisted yet and nor are A or B. Once Graph is sent to the server, they are all persisted. A new Graph is persisted that has a different A but the same B. It does not realise that B has already been persisted and re-creates it even though it has the same @Id.
I have a feeling that JPA does not see the object as the same as the same as the in memory one.
I am sure that OpenJPA 1.2 seemed to recognise the objects as equivalent based on the @Id annotation. I have tried fixing up the references manually and trying to change the references from the unmanaged objects to the managed ones loaded in memory on the server. Unfortuantely this works until I restart the server and it doesn't fix up references that were made before. I know this is not the proper solution.
How do I go about solving this?
- I am using GWT's serialization and that works fine. Could GWT cause this? I think this a JPA problem.
It's time to use a DTO considering you have some referential logic that should happen after getting an object back to the server.
You can create a Graph_Model, A_Model, and B_Model classes (these are the Data Transfer Objects), and use these when talking to the client side GWT code. When a Graph_Model
comes to the server, you can then create a managed Graph
object from the Graph_Model, and set correct references by making queries.
Also it is kind of odd that class A and Graph do not have an ID property at all, so they will be created whenever you save an object of type Graph. I don't have enough info to suggest anything else, without knowing what is it that you are trying to do, the objective.
精彩评论