Hibernate Natural ID duplication issue

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.

+6
source share
2 answers

As the Beatles said, when you tell Hibernate that you have a natural key, it tells the DB to ensure uniqueness. Uniqueness in this case is accomplished by creating an exception of the type you saw (MySQLIntegrityConstraintViolationException).

The only way I know with is to first try and first get an object that matches your business identity (TestId equal), and then work with either this instance if it is found, or with a new instance if it is not. Hibernate does not automatically do this for you.

+2
source

When you mark some fields as “Identical identifier”, this means that in this context the combination of these fields will be unique, therefore, for example, if you have a class called a person who has FirstName and LastName as Natural ID, there can only be one a person having John as his FirstName and Smith as his LastName (it looks like a unique index)

In your code:

 TestId id1 = new TestId(1,2,3); 

and

 TestId id2 = new TestId(1,2,3); 

refer to two different objects with the same Natural identifier, so they cannot be stored in the database.

+1
source

Source: https://habr.com/ru/post/888538/


All Articles