我们正在使用看起来像这样的JPA注释类型(groovy代码):
@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提供程序(在我的情况下,hibernate)可以正确地为我生成DDL,以防我们想要交换数据库。它还准确记录了我想要的文本字段。现在,当一个笔记被创建时,我看到这样的东西:
id | text
-----+------------------------
837 | 33427
对于新笔记来说这很好,因为当我使用String 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中是否有一种方法可以迁移旧笔记以正确使用@Lob
和text
类型?提前谢谢。
答案 0 :(得分: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通常不会将文本存储为五位整数。 :)
答案 1 :(得分:8)
我使用JPA来注释我的实体,并使用hibernate来持久保存它们。但我不想在我的实体中添加特定于hibernate的注释。因此,我有一个包含实体+注释的数据jar。然后在我的实现中,我指定persistence.xml并添加一个'CustomTypes.hbm.xml'。这是通过persistence.xml中的mapping-file标记自动扫描或添加的。
此映射包含我要从basictyperegistry覆盖的类型。 在这种情况下,使用materialized_clob类型。我不想要,因为当我使用查询工具浏览我的数据库时,我希望能够直接查看实际内容。 所以我补充说:
<typedef name="materialized_clob" class="org.hibernate.type.TextType" />
强制为所有clob使用指定的类型,而无需在我的数据包中添加特定的注释。
您可以通过在DEBUG级别上记录org.hibernate.type.BasicTypeRegistry来查看映射。
花了一些时间来解决这个问题,我希望这可以帮助任何面临同样问题的人。因为这可能也会解决你的问题,我认为可能值得在这里发布。
答案 2 :(得分:1)
我确信它已经很晚了,但对于今后遇到同样问题的人来说。
我还遇到了一个类似的问题,我在文本列中的旧数据直接在列中而不是作为OID。当我试图在升级后的应用程序中使用该数据时,我也得到了
Bad value for type long
要解决此问题,我创建了this script。可能它可以在将来帮助某人。
我从这篇文章获得了很大的帮助here
答案 3 :(得分: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
,只需使用@Lob
注释String属性并使用CustomSessionFactoryBean