11

我们正在使用一个看起来像这样的 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 提供程序(在我的例子中是休眠)可以为我正确生成 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 中有没有办法迁移旧笔记以正确使用@Lobtext键入?提前致谢。

4

4 回答 4

13

根据Postgres 大对象文档,您似乎必须将每个文本块写入文件并单独导入。这不是你应该在 SQL 中做的事情。

我对JPA一无所知,但是@Lob与DDL或切换数据库有什么关系?您已经完全改变了列的类型;Postgres 的text类型有什么问题?


在这里关闭循环,这样评论就不会丢失:

真正的问题是@Lob创建了一个 Postgrestext列,但Hibernate 将其视为一个本地 Postgres“大对象”,它将数据存储在其他地方并且只在表中留下一个 oid(然后根据列类型存储为文本)。这通常不是您想要的文本。

OP 的解决方案是@Type(type="org.hibernate.type.StringClobType")强制 Hibernate 存储常规文本。

Postgres 通常不将文本存储为五位整数。:)

于 2013-01-25T00:10:32.213 回答
8

我使用 JPA 来注释我的实体并使用休眠来持久化它们。但我不想向我的实体添加特定于休眠的注释。因此,我有一个包含实体 + 注释的数据 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 来查看映射。

我花了一些时间来解决这个问题,我希望这能帮助任何面临同样问题的人。因为这可能也会解决您的问题,所以我认为可能值得在这里发布。

于 2013-06-25T12:19:13.887 回答
2

我相信它已经晚了,但是对于将来遇到同样问题的任何人。

我也遇到了类似的问题,我在文本列中有旧数据,而不是 OID。当我尝试将这些数据与升级的应用程序一起使用时,我也得到了

Bad value for type long

为了解决这个问题,我创建了这个脚本。也许它可以在将来帮助某人。

我从这里的这篇文章中得到了很大的帮助

于 2015-04-07T05:22:27.493 回答
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

于 2014-09-30T11:19:06.583 回答