title: Hibernate Natural ID duplicate issue
body: <p>I'm new to Hibernate and DBs in general, so pardon the elementary question.</p>
  
  <p>I am working with the <a href="http://en.wikipedia.org/wiki/Distributed_Interactive_Simulation" rel="noreferrer">DIS protocol</a> and specifically the Open-DIS implementation of DIS.  In DIS, each EntityStatePdu (containing the state of an entity in the simulation) has an EntityId object, a tuple of 3 integers.  I want to use this object as a Natural Id, and maintain a standard surrogate ID as well.  My problem is I cannot figure out how to ensure that the DB determines that a given EntityId already exists and use that EntityId's primary key as the foreign key in the EntityStatePdu.</p>
  
  <p>In other words, say I have two EntityStatePdus, with EntityID (1, 2, 3); i.e. we have two updates from the same entity.  I would want something like the following:</p>
  
  <p>tables:</p>
  
  <pre><code>entity_id 
  pk   site   app    entity
  0    1      2      3
  
  
  entity_state_pdu
  pk  entity_id_fk  timestamp
  0   0             1
  1   0             2
  </code></pre>
  
  <p>Here are the simplified classes I am testing with:</p>
  
  <pre><code>@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;
      }
  }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>@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;
      }
  }
  </code></pre>
  
  <p>I attempt to store two TestEntity objects into the DB with two separate TestId objects (which are equal in terms of having the same site, app, and entity) in the following way:</p>
  
  <pre><code>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();
  }
  </code></pre>
  
  <p>I get a long stack trace on the session2.save(entity2) line, with the salient line being </p>
  
  <pre><code>com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '2-3-1' for key 'app'
  </code></pre>
  
  <p>I hope this is clear enough.  Thank you.</p>