2012-09-20 77 views
12

在標題中有很多說明。我有一個類,它看起來是這樣的:如何在休眠中將字符串映射到DB序列

@Entity 
@Table(name="FOO") 
public class Foo { 

    private String theId; 

    @Id 
    @Column(name = "FOO_ID") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "fooIdSeq") 
    @SequenceGenerator(name = "fooIdSeq", sequenceName = "SQ_FOO_ID", allocationSize = 10) 
    public String getTheId() { return theId; } 

    public String setTheId(String theId) { this.theId = theId; } 
} 

使用Oracle 11g中,FOO_ID列是VARCHAR2,但序列SQ_FOO_ID產生一個NUMBER。數據庫顯然對此感到滿意,但應用程序需要能夠支持在應用程序之外可能插入此列的非數字ID。

考慮到上面的代碼,我得到一個org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String。有沒有辦法做這個映射?

使用Hibernate 3.6。

回答

10

實現一個自定義的IdentifierGenerator類;從blog post

import java.io.Serializable; 
import java.sql.Connection; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 

import org.hibernate.HibernateException; 
import org.hibernate.engine.spi.SessionImplementor; 
import org.hibernate.id.IdentifierGenerator; 

public class StringKeyGenerator implements IdentifierGenerator { 

    @Override 
    public Serializable generate(SessionImplementor session, Object collection) throws HibernateException { 
     Connection connection = session.connection(); 
     PreparedStatement ps = null; 
     String result = ""; 

     try { 
      // Oracle-specific code to query a sequence 
      ps = connection.prepareStatement("SELECT TABLE_SEQ.nextval AS TABLE_PK FROM dual"); 
      ResultSet rs = ps.executeQuery(); 

      if (rs.next()) { 
       int pk = rs.getInt("TABLE_PK"); 

       // Convert to a String 
       result = Integer.toString(pk); 
      } 
     } catch (SQLException e) { 
      throw new HibernateException("Unable to generate Primary Key"); 
     } finally { 
      if (ps != null) { 
       try { 
        ps.close(); 
       } catch (SQLException e) { 
        throw new HibernateException("Unable to close prepared statement."); 
       } 
      } 
     } 

     return result; 
    } 
} 

註釋實體PK這樣的:

@Id 
@GenericGenerator(name="seq_id", strategy="my.package.StringKeyGenerator") 
@GeneratedValue(generator="seq_id") 
@Column(name = "TABLE_PK", unique = true, nullable = false, length = 20) 
public String getId() { 
    return this.id; 
} 

由於在Eclipse的錯誤,錯誤可能會升高,發電機(seq_id)在持久性單元沒有被定義。如下設置爲先發出警告:

  1. 選擇窗口»首選項
  2. 展開Java持久性»JPA»錯誤/警告
  3. 點擊查詢和發電機
  4. 設置發生器是未在持久化單元中定義至:Warning
  5. 點擊OK應用更改並關閉對話框
3

這是另一種方法:

import java.io.Serializable; 

import org.hibernate.engine.spi.SessionImplementor; 
import org.hibernate.id.IdentifierGeneratorHelper.BigDecimalHolder; 
import org.hibernate.id.IntegralDataTypeHolder; 
import org.hibernate.id.SequenceGenerator; 

public class StringSequenceGenerator extends SequenceGenerator { 
    @Override 
    public Serializable generate(SessionImplementor session, Object obj) { 
     return super.generate(session, obj).toString(); 
    } 

    protected IntegralDataTypeHolder buildHolder() { 
     return new BigDecimalHolder(); 
    } 
} 

序列參數必須在id屬性像在下面的例子中規定:

@Id 
@GenericGenerator(name = "STRING_SEQUENCE_GENERATOR", strategy = "mypackage.StringSequenceGenerator", parameters = { @Parameter(name = "sequence", value = "MY_SEQUENCE_NAME") }) 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "STRING_SEQUENCE_GENERATOR") 
@Column(name = "MY_ID") 
public String getMyId() { 
    return this.myId; 
}