I am new to Hibernate and DB in general, so I apologize for the elementary question.
I work with the DIS protocol and, in particular, the DIS DIS program. In DIS, each EntityStatePdu (containing the state of the object in the simulation) has an EntityId object, a tuple of 3 integers. I want to use this object as an Identity Identifier, and also support a standard surrogate identifier. My problem is that I cannot figure out how to make sure that the database determines that the given EntityId already exists and uses this primary key EntityId as a foreign key in EntityStatePdu.
In other words, let's say I have two EntityStatePdus, with EntityID (1, 2, 3); that is, we have two updates from the same object. I would like something like the following:
tables:
entity_id pk site app entity 0 1 2 3 entity_state_pdu pk entity_id_fk timestamp 0 0 1 1 0 2
Here are the simplified classes I'm testing:
@Entity public class TestEntity { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @NaturalId @ManyToOne(cascade = CascadeType.ALL) private TestId naturalId; public Long getId() { return id; } public void setId(long id) { this.id = id; } public TestId getNaturalId() { return naturalId; } public void setNaturalId(TestId naturalId) { this.naturalId = naturalId; } }
and
@Entity public class TestId { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @NaturalId private int site; @NaturalId private int app; @NaturalId private int entity; public TestId(int site, int app, int entity) { this.site = site; this.app = app; this.entity = entity; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public int getSite() { return site; } public void setSite(int site) { this.site = site; } public int getApp() { return app; } public void setApp(int app) { this.app = app; } public int getEntity() { return entity; } public void setEntity(int entity) { this.entity = entity; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + app; result = prime * result + entity; result = prime * result + site; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TestId other = (TestId) obj; if (app != other.app) return false; if (entity != other.entity) return false; if (site != other.site) return false; return true; } }
I am trying to save two TestEntity objects in a database with two separate TestId objects (which are equal in terms of having the same site, application and object) as follows:
public static void main(String[] args) { SessionFactory factory = createFactory(); Session session = factory.openSession(); Transaction tx = session.beginTransaction(); TestId id1 = new TestId(1,2,3); TestEntity entity1 = new TestEntity(); entity1.setNaturalId(id1); session.save(entity1); tx.commit(); session.close(); Session session2 = factory.openSession(); Transaction tx2 = session2.beginTransaction(); TestId id2 = new TestId(1,2,3); TestEntity entity2 = new TestEntity(); entity2.setNaturalId(id2); session2.save(entity2); tx2.commit(); session2.close(); }
I get a long stack trace in session2.save (entity2) line with highlighted line
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '2-3-1' for key 'app'
Hope this is clear enough. Thanks.