I have some serious issues with JPA. We are using Vaadin and JPA (EclipseLink 2.5.0)
In my application i have a treebased datastructure. I get from a rest interface new data, put them into a queue, get them with another thread out of the queue and update the nodes in tree which already are in with the new values, those which are new are getting added into the tree. Then i save the parent tree (called System) and with cascade it should save all child nodes into the database. Works fine. Sometimes.
Here is some code snippet of the thread which is saving and adding to the tree:
public void updateDatastructure(System connectedSystem, System receivedSystem) {
if (connectedSystem != null) {
boolean needRMUpdate = false;
dao.createEntityManager();
dao.beginTransaction();
for (Node receivedNode : receivedSystem.getNodes().values()) {
Node nodeInTree = connectedSystem.getNode(receivedNode.getName());
if (nodeInTree == null) {
addStructure(receivedNode, connectedSystem);
needRMUpdate = true;
} else if (nodeInTree != null) {
updateStructure(nodeInTree, receivedNode);
}
}
dao.commitTransaction();
dao.closeEntityManager();
triggerChangesOfHistoryDatas(historysizedData);
historysizedData.clear();
// RuleManager: Update the RuleManager
if (needRMUpdate)
XXX_Initializer.ruleManager.addOrUpdateSystem(connectedSystem);
}
}
The UpdateDatastructure method is called every 10 seconds.
The structure of my Tree looks like that:
System - Node - Data
Above the System node are another nodes but that doesnt matter at the moment.
System does have 0..* Nodes Node does have 0..* Nodes Node does have 0..* Data Data is leaf
@Entity
@Table(name = "node")
@NamedQuery(name = "node.findAll", query = "SELECT n FROM Node n")
public class Node implements TreeNodeBase, Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "NAME", nullable = false)
private String name;
private String path;
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER)
@MapKey(name = "name")
@JoinColumn(name = "PARENT_ID", referencedColumnName = "id")
private Map<String, Node> nodes = new HashMap<String, Node>();
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER)
@MapKey(name = "name")
@JoinColumn(name = "NODE_ID", referencedColumnName = "id")
private Map<String, Data> datas = new HashMap<String, Data>();
@ManyToOne
@JoinColumn(name = "SYSTEM_ID", referencedColumnName = "id")
private System system;
@ManyToOne
@JoinColumn(name = "PARENT_ID", referencedColumnName = "id")
private Node parentNode;
The datastructure (tree) is always in memory, because multiple user can login into the application and need that data from the tree.
I guess that means i need to let the whole tree managed right?
So is it wrong to use the entityManager like this?
Main Question: Why duplicates the JPA / EclipseLink sometimes "node" sometimes "data" and sometimes "system", but with different IDs.
Here are some screenshots of the database tables:
Edit Node Hash and Equals:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((parentNode == null) ? 0 : parentNode.hashCode());
result = prime * result + ((system == null) ? 0 : system.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (parentNode == null) {
if (other.parentNode != null)
return false;
} else if (!parentNode.equals(other.parentNode))
return false;
if (system == null) {
if (other.system != null)
return false;
} else if (!system.equals(other.system))
return false;
return true;
}