title: Hibernate JPA data persistence and mapping Foreign key
body: <p>i would like to ask few question about Hibernate/jpa data persistence. so here's my two principal problems:</p>
  
  <p>1) i'm using hibernate to persist an enumeration using a generic user type and a tuplizer, and this is my sample code :</p>
  
  <hr>
  
  <h2>generic enum persistence type :</h2>
  
  <pre><code>import javax.persistence.Cacheable;
  import javax.persistence.Column;
  import javax.persistence.Entity;
  import javax.persistence.Id;
  
  import lombok.AccessLevel;
  import lombok.AllArgsConstructor;
  import lombok.Getter;
  
  import org.hibernate.annotations.Cache;
  import org.hibernate.annotations.CacheConcurrencyStrategy;
  import org.hibernate.annotations.Tuplizer;
  
  import com.jimmy.htf.util.GenericEnumTuplizer;
  
  @Entity
  @Cacheable
  @Tuplizer(impl = GenericEnumTuplizer.class)
  @AllArgsConstructor(access = AccessLevel.PRIVATE)
  @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
  public enum Language  {
  
      ARABIC(1, "language.arabic"), BULGARIAN(2, "language.bulgarian"), CATALAN(3, "language.catalan"), CHINESE(4, "language.chinese"), CROATIAN(5, "language.croatian"), CZECH(6, "language.czech"),
      DANISH(7, "language.danish"), DUTCH(8, "language.dutch"), ENGLISH(9, "language.english"), FINNISH(10, "language.finnish"), FRENCH(11, "language.french"), GERMAN(12, "language.german"),
      GREEK (13, "language.greek"), HEBREW(14, "language.hebrew"), HUNGARIAN(15, "language.hungarian"), INDONESIAN(16, "language.indonesian"), ITALIAN(17, "language.italian"), 
      JAPANESE(18, "language.japanese"), KOREAN(19, "language.korean"), LITHUANIAN(20, "language.lithuanian"), NORWEGIAN(21, "language.norwegian"), PERSIAN(22, "language.persian"), 
      POLISH(23, "language.polish"), PORTUGUESE(24, "language.portuguese"), ROMANIAN(25, "language.romanian"), RUSSIAN(26, "language.russian"), SERBIAN(27, "language.serbian"), 
      SLOVAK(28, "language.slovak"), SLOVENIAN(29, "language.slovenian"), SPANISH(30, "language.spanish"), SWEDISH(31, "language.swedish"), TURKISH(32, "language.turkish"),
      THAI(33, "language.thai"), UKRAINIAN(34, "language.ukrainian"), VIETNAMESE(35, "language.vietnamese"), OTHER(36, "language.other");
  
      @Id
      @Getter
      private Integer codeValue;
  
      @Getter
      @Column(length = 64)
      private String  I18nGlobalMessage;
  
      public static Language fromValue(Integer value) {
          switch (value) {
              case 1: return ARABIC; 
              case 2: return BULGARIAN;
              case 3: return CATALAN;
              case 4: return CHINESE;
              case 5: return CROATIAN;
              case 6: return CZECH;
              case 7: return DANISH;
              case 8: return DUTCH;
              case 9: return ENGLISH;
              case 10: return FINNISH;
              case 11: return FRENCH;
              case 12: return GERMAN;
              case 13: return GREEK;
              case 14: return HEBREW;
              case 15: return HUNGARIAN;
              case 16: return INDONESIAN;
              case 17: return ITALIAN;
              case 18: return JAPANESE;
              case 19: return KOREAN;
              case 20: return LITHUANIAN;
              case 21: return NORWEGIAN;
              case 22: return PERSIAN;
              case 23: return POLISH;
              case 24: return PORTUGUESE;
              case 25: return ROMANIAN;
              case 26: return RUSSIAN;
              case 27: return SERBIAN;
              case 28: return SLOVAK;
              case 29: return SLOVENIAN;
              case 30: return SPANISH;
              case 31: return SWEDISH;
              case 32: return TURKISH;
              case 33: return THAI;
              case 34: return UKRAINIAN;
              case 35: return VIETNAMESE;
              case 36: return OTHER;
              default: return null;
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <h2>generic enum tuplizer</h2>
  
  <pre><code>import java.io.Serializable;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  import org.hibernate.mapping.PersistentClass;
  import org.hibernate.tuple.Instantiator;
  import org.hibernate.tuple.entity.EntityMetamodel;
  import org.hibernate.tuple.entity.PojoEntityTuplizer;
  
  public class GenericEnumTuplizer extends PojoEntityTuplizer {
  
      public GenericEnumTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
          super(entityMetamodel, mappedEntity);
      }
  
      @Override
      @SuppressWarnings(value = { "unchecked", "rawtypes"})
      protected Instantiator buildInstantiator(final PersistentClass persistentClass) {
          return new Instantiator() {
              @Override
              public Object instantiate(Serializable id) {
                  try {
                      Class enumClass = getMappedClass();
                      String identifierMethodName = GenericEnumPersistenceType.DEFAULT_CODE_VALUE_METHOD_NAME;
                      Method codeValueMethod = enumClass.getMethod(identifierMethodName, new Class[0]);
                      Class&lt;?&gt; codeValueType = codeValueMethod.getReturnType();
                      String valueOfMethodName = GenericEnumPersistenceType.DEFAULT_FROM_VALUE_METHOD_NAME;
                      Method fromValueMethod = enumClass.getMethod(valueOfMethodName, new Class[] { codeValueType });
                      return fromValueMethod.invoke(enumClass, id); 
                  } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                      throw new AssertionError(e);
                  }
              }
  
              @Override
              public Object instantiate() {
                  throw new UnsupportedOperationException();
              }
  
              @Override
              public boolean isInstance(Object object) {
                  throw new UnsupportedOperationException();
              }
          };
      }
  }
  </code></pre>
  
  <hr>
  
  <h2>generic enum persistence type</h2>
  
  <pre><code>import java.io.Serializable;
  import java.lang.reflect.Method;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Types;
  import java.util.Properties;
  
  import org.apache.commons.lang.ObjectUtils;
  import org.hibernate.HibernateException;
  import org.hibernate.engine.spi.SessionImplementor;
  import org.hibernate.type.IntegerType;
  import org.hibernate.usertype.ParameterizedType;
  import org.hibernate.usertype.UserType;
  
  public class GenericEnumPersistenceType&lt;E&gt; implements UserType, ParameterizedType {
      public static final String DEFAULT_CODE_VALUE_METHOD_NAME = "getCodeValue";
      public static final String DEFAULT_FROM_VALUE_METHOD_NAME = "fromValue";
      private Method codeValueMethod;
      private Method fromValueMethod;
      private Class&lt;?&gt; codeValueType;
      private Class&lt;E&gt; enumClass; 
  
      public GenericEnumPersistenceType(){}
  
      @Override
      @SuppressWarnings("unchecked")
      public void setParameterValues(Properties parameters) {
          String enumClassName = parameters.getProperty("enumClass");
          try {
              enumClass =  (Class&lt;E&gt;) Class.forName(enumClassName).asSubclass(Enum.class);
          } catch (ClassNotFoundException e) {
              throw new HibernateException("Enum class not found", e);
          }
          String identifierMethodName = parameters.getProperty("codeValueMethod", DEFAULT_CODE_VALUE_METHOD_NAME);
          try {
              codeValueMethod = enumClass.getMethod(identifierMethodName, new Class[0]);
              codeValueType = codeValueMethod.getReturnType();
          } catch (Exception e) {
              throw new HibernateException("Failed to obtain codeValue method. Setting default method name", e);
          }
          String valueOfMethodName = parameters.getProperty("fromValueMethod", DEFAULT_FROM_VALUE_METHOD_NAME);
          try {
              fromValueMethod = enumClass.getMethod(valueOfMethodName, new Class[] { codeValueType });
          } catch (Exception e) {
              throw new HibernateException("Failed to obtain fromValue method. Setting default method name", e);
          }
      }
  
      @Override
      public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
          try {
              String propertyValue = resultSet.getString(names[0]);
              Integer propertyNumericValue;
              try {
                  propertyNumericValue = Integer.valueOf(propertyValue);
              } catch (NumberFormatException e) {
                  return null;
              }
              return fromValueMethod.invoke(enumClass, propertyNumericValue); 
          } catch (Exception e) {
              e.printStackTrace();
              throw new HibernateException("Exception while invoking valueOf method '" + fromValueMethod.getName() + "' of " + "enumeration class '" + enumClass + "'", e);
          }
      }
  
      @Override
      public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
          try {
              if (null == value) {
                  preparedStatement.setNull(index, Types.INTEGER);
              } else {
                  Object identifier = codeValueMethod.invoke(value, new Object[0]);
                  preparedStatement.setInt(index, (Integer) identifier);
              }
          } catch (Exception e) {
              e.printStackTrace();
              throw new HibernateException("Exception while invoking identifier method '" + codeValueMethod.getName() + "' of " + "enumeration class '" + enumClass + "'", e);
          }
  
      }
  
      @Override
      public Class&lt;E&gt; returnedClass() {
          return enumClass;
      }
  
      @Override
      public int[] sqlTypes() {
           return new int[] { IntegerType.INSTANCE.sqlType() };
      }
  
      @Override
      public boolean isMutable() {
          return false;
      }
  
      @Override
      public boolean equals(Object x, Object y) throws HibernateException {
          return ObjectUtils.equals(x, y);
      }
  
      @Override
      public int hashCode(Object x) throws HibernateException {
          assert (x != null);
          return x.hashCode();
      }
  
      @Override
      public Object deepCopy(Object value) throws HibernateException {
          return value;
      }
  
      @Override
      public Object replace(Object original, Object target, Object owner) throws HibernateException {
          return original;
      }
  
      @Override
      public Serializable disassemble(Object value) throws HibernateException {
          return (Serializable) value;
      }
  
      @Override
      public Object assemble(Serializable cached, Object owner) throws HibernateException {
          return cached;
      }
  
  }
  </code></pre>
  
  <hr>
  
  <p>well now, everything is working just fine with this classes. what i need is to do some improvement:</p>
  
  <p>since i have my languages in my enum and DB tables as well:</p>
  
  <p>----> Language[] languages = Language.values(); (Language is the name of the enum above )</p>
  
  <p>i want to use objects directly from my enumeration without retriving the entity from the database:
  in other words, i want to do this:</p>
  
  <p>Set spokenLanguages = new HashSet();
      spokenLanguages.add(Language.ENGLISH);
      subscribe</p>
  
  <p>r.setSpokenLanguages(spokenLanguages);</p>
  
  <p>instead of doing this: </p>
  
  <p>Set spokenLanguages = new HashSet();
      spokenLanguages.add(languageService.getLanguageById(Language.ENGLISH.getCodeValue()));
      subscribe</p>
  
  <p>r.setSpokenLanguages(spokenLanguages);</p>
  
  <p>i want to bypass the dao usage and database access, but everytime i do that i get an exception because the element is inserted in DB and the id already exists obviously.</p>
  
  <p>even if the Id isn't autogenerated, Hibernate still insert the element if it's not retrived from DB. so i wonder if there's a way to handle this case, or if there's a solution that can be imgined like a class initializing the whole application at start up and loading the languages list from DB and not from the Enum.</p>
  
  <p>2 ) </p>
  
  <p>i'm using JPA 2.0 mapping. using hibernate-jpa-2.0 and hibernate 4.1.0.final</p>
  
  <p>i have a @ManyToOne relation between my 2 classes : EventPicture --> Event</p>
  
  <pre><code>    @ManyToOne
  @JoinColumn(name = "event")
  @ForeignKey(name = "event_foreign_Key")
  private Event event;
  </code></pre>
  
  <p>event is a private property in eventPicture to map the owning event
  and i'm having this message which i don't understand, i made some reserches but found nothing about it;</p>
  
  <pre><code> Foreign key "{0}" not found in the table "{1}"
  </code></pre>
  
  <p>Any help would be appreciated.
  Thanks</p>