2013-01-24 32 views
10

我們使用JPA註釋類型看起來像這樣(Groovy代碼):如何將PostgreSQL字符串遷移到文本類型?

@Entity 
@EqualsAndHashCode 
class TextNote extends Serializable { 
    @Id Long id 
    String text 
} 

當它第一次寫我是很新的JPA和寫的SQL第一,遂作出上述註釋類匹配SQL。 PostgreSQL的讀了它好像下面是我想要的表:

CREATE TABLE textnote (
    id bigint NOT NULL, 
    text text 
); 

這個工作,我們有一個看起來像這樣的表:

id |   text 
-----+------------------------ 
837 | really long text here 

我想現在要做的是正確的JPA實體,看起來像這樣:

@Entity 
@EqualsAndHashCode 
class TextNote extends Serializable { 
    @Id Long id 
    @Lob String text 
} 

通過添加@Lob註釋JPA提供者(在我的情況下,休眠)能夠在正確的情況下產生的DDL我我們想換出數據庫。它也準確地記錄了我想要的文本字段。現在,當音符越創建我看到這樣的事情:

id |   text 
-----+------------------------ 
837 | 33427 

這是精細新音符,當我在代碼中使用字符串的getText(閱讀),它返回的很長的文字。老實說,我不知道PostgreSQL如何實現text類型,理論上也不需要。然而,我們的生產數據庫已經有很多使用舊代碼存儲的註釋,而沒有@Lob註釋。運行現有數據庫的新代碼產生的問題是這樣的:

org.springframework.dao.DataIntegrityViolationException: Bad value for type long : not a number this time; SQL [n/a]; nested exception is org.hibernate.exception.DataException: Bad value for type long : not a number this time 

對於現有的筆記,有沒有在SQL的方式遷移舊鈔正確使用@Lobtext類型?提前致謝。

回答

12

基於Postgres large object docs它看起來像你必須寫每個文本塊到一個文件並單獨導入它。這不是你應該在SQL中做的事情。

我對JPA一無所知,但@Lob與DDL或交換數據庫有什麼關係?你已經完全改變了列的類型; Postgres的text類型有什麼問題?


這裏關閉循環,使這不是失去了評論:

真正的問題是,@Lob創建一個Postgres text列,但Hibernate treats it作爲原生Postgres的「大目標」而在其他地方存儲數據並且只留下表格中的一個oid(然後按照列類型將其存儲爲文本)。這通常不是你想要的文字。

OP的解決方案是打電話給@Type(type="org.hibernate.type.StringClobType")強制Hibernate存儲常規文本。

Postgres通常不會將文本存儲爲五位整數。 :)

+0

如果沒有這個註釋,JPA提供者會產生與列varchar類型的表,這不是我想要的。 '@ Lob'生成PostgreSQL'text'類型,這正是我想要的。如果我想切換數據庫,我想使用JPA提供程序爲我生成DDL。爲了做到這一點,'@ Lob'是必要的。合理? – Joe

+0

你確定'@ Lob'正在生成'text'嗎?文檔和發佈的輸出都讓我認爲它會生成'oid' - 這就是Postgres如何存儲大型對象。如果它真的是「文本」,你只會看到_text_,而不是一個神祕的數字。 – Eevee

+0

我很積極,這裏是它用'@ Lob'註釋輸出的表格: [gist](https://gist.github.com/4630173) – Joe

7

我使用JPA註釋我的實體和冬眠來堅持他們。但我不想爲我的實體添加hibernate特定的註釋。因此,我有一個包含實體+註釋的數據jar。然後在我的實現中指定persistence.xml並添加一個'CustomTypes.hbm.xml'。它是通過persistence.xml中的映射文件標籤自動掃描或添加的。

該映射包含我想要從basictyperegistry覆蓋的類型。 在這種情況下,使用materialized_clob類型。我不想要,因爲當我用查詢工具瀏覽我的數據庫時,我希望能夠直接查看實際內容。 所以我想補充:

<typedef name="materialized_clob" class="org.hibernate.type.TextType" /> 

要強制所有的CLOB使用指定的類型,而不需要在我的數據包添加特定的註釋。

您可以通過在DEBUG級別上記錄org.hibernate.type.BasicTypeRegistry來查看映射。

我花了一些時間來弄清楚這一點,我希望這會幫助任何面臨相同問題的人。因爲這可能也會解決你的問題,我認爲這可能值得在這裏發佈。

0

如果使用spring,你可以創建LocalSessionFactoryBean後代來注入Hibernate類型的覆蓋。見例如:

public class CustomSessionFactoryBean extends LocalSessionFactoryBean { 

    @Override 
    protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) { 
     // To store @Lob annotated Strings in TEXT fields. 
     // By default for Postgres generated TEXT column, but stored OID of Postgres LOB object 
     sfb.registerTypeOverride(new TextType() { 
      @Override 
      public String getName() { 
       return StandardBasicTypes.MATERIALIZED_CLOB.getName(); 
      } 
     }); 
     sfb.registerTypeOverride(new NTextType() { 
      @Override 
      public String getName() { 
       return StandardBasicTypes.MATERIALIZED_NCLOB.getName(); 
      } 
     }); 

     super.buildSessionFactory(sfb); 
    } 
} 

你不需要使用Hibernate的具體詮釋@Type,只是標註String屬性@Lob和使用CustomSessionFactoryBean

1

我相信它的晚,但對任何人有在未來同樣的問題。

我也遇到了類似的問題,我在列中直接在列中的舊數據而不是OID。當我嘗試使用與升級的應用程序的數據我也漸漸

Bad value for type long 

要解決此我創建this script。可能會對未來有所幫助。

我得到了很大的幫助,從這個帖子here

相關問題