JPA注解@Column(insertable=false)被忽略了,为什么?

7

当调用save()方法时,我希望其中一个字段被忽略。该字段将由数据库自动填充并返回。它应被视为只读字段。

我关注private Timestamp ts;字段:

@Entity
@Table(name = "time_series", schema = "ms")
@IdClass(Reading.class)
public class Reading implements Serializable {

   private static final long serialVersionUID = 1L;

   @Id
   @Column(name = "name", nullable = false)
   private String sensorName;

   @Id
   @Column(name = "ts", insertable = false, updatable = false)
   private Timestamp ts;

   @Column(name = "reading")
   private Double value;
   ...

从代码中可以看到,我在@Column注解中使用了insertable = false, updatable = false,因此我希望在实际的SQL语句中忽略ts

@Override
@Transactional(readOnly = false)
public Reading save(Reading r) {        
    return readingRepository.save(r);
}

ReadingRepository 基本上是扩展了 Spring 的 CrudRepository,它有一个 save(...) 方法。

当我使用 ts=null 保存 Reading 对象时,从 Postgres 中得到错误:

ERROR: null value in column "ts" violates not-null constraint

因为 Spring Data 实际上没有忽略基于日志所看到的 ts 字段:

insert into ms.time_series (ts, name, reading) values (NULL, 'sensor1', 10.0)

显然,我希望查询不包含ts,像这样:

insert into ms.time_series (name, reading) values ('sensor1', 10.0)

为什么这个字段没有被忽略?

如果你问我我的数据库模式是否没问题,我会回答是的。当我在控制台中键入SQL查询时,没有ts的情况下一切正常。我甚至尝试了@Generated@GeneratedValue注释。Namets都形成了表的主键,然而,即使我只将它们中的一个设置为PK,或者添加额外的代理ID列,结果仍然相同......

我是否漏看了什么,还是Spring框架可能存在缺陷?我使用的是Spring 5.1.2和SpringData 2.1.2。

注意:如果我使用@Transient注释,则可以正确持久化插入查询,但是该字段在读取/提取时完全被忽略。

非常感谢您对此的任何帮助!


在你的时间戳字段上使用@Transient注释。 - Angad Bansode
如果它既不可插入也不可更新,那么它怎么可能是“null”?另外,你的映射很奇怪,@IdClass 怎么可能与实体类相同? - M. Deinum
@M.Deinum 我不得不添加 @IdClass,这样我就可以在这里有两个 @Id。正如我所提到的,当我删除它时,错误仍然存在。 - user3732445
我知道@IdClass的作用,但它应该是一个独立的类而不是指向实体。此外,需要插入一个未生成的@Id(你需要指定)。所以基本上你的映射是冲突的。你不想要一个生成的值,但也不想将其插入。因此,Hibernate需要做出决策。 - M. Deinum
@AngadBansode,请阅读我的帖子,我不能使用@Transient,因为我需要能够获取和读取该值。 - user3732445
@M.Deinum 非常感谢!我猜那一定是问题所在。我会尝试将其移动到不同的类中来修复它... - user3732445
2个回答

0

尝试在您的代码中使用GenericGeneratorGeneratedValue

在Reading类中添加所需的注释,并为除ts之外的所有其他成员赋值。

这里有一些示例


谢谢!我尝试了那个,但它没有起作用,也许我还没有想出正确的选择排列方式。 - user3732445
无论如何,将javax.persistence.*和org.hibernate.annotations.*注解混合使用是一个好主意吗?GeneratedValue是javax的,而GenericGenerator是hibernate的。 - user3732445

-1

正如你所说

我从Postgres得到一个错误

如果你查看文档,它指出:

从技术上讲,主键约束只是唯一约束和非空约束的组合。

对于多列主键也是如此(请参见此处

因此,如果ts是数据库中主键的一部分(如@Id所示),则无法在该列中插入空值。

在我看来,Hibernate/Spring与此无关

insert into ms.time_series (ts, name, reading) values (NULL, 'sensor1', 10.0)

应该等同于

insert into ms.time_series (name, reading) values ('sensor1', 10.0)

1
如果Hibernate/Spring与此无关,则发送的SQL查询应该没有“ts”。我还说过,我尝试使“ts”不成为主键的一部分,但错误仍然存在。 - user3732445
1
为什么要使用当前时间来创建时间戳,将其转换为文本再将其转换为时间戳?背后的原因是什么? - M. Deinum
1
@M.Deinum 我从其他地方复制粘贴了这段代码,我会进行修复,但我不认为它是问题的原因。问题在于Spring/Hibernate发送了一个不正确的SQL查询,可能是由于我不正确地使用注释或框架本身存在的错误引起的。 - user3732445
@M.Deinum 您说得对,Hibernate 确实感到困惑。我猜我需要尝试一下 @GeneratedValue,但我不知道该怎么做。无论我将其设置为 AUTO、IDENTITY 还是 TABLE,它仍然无法正常工作。您有任何关于如何正确设置的想法吗? - user3732445
1
@M.Deinum,我已经尝试了所有可能的方法。包括使用@GeneratedValue@TableGenerator的所有排列组合。我已经花了3天的时间在这个问题上,所以我也开了这个帖子https://stackoverflow.com/questions/53290636/how-to-set-up-jpa-annotations-to-generate-id-primary-key-on-the-database-level 我感到非常绝望。 - user3732445
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接