在持久性期间忽略JPA字段的最简单方法是什么?


281

我本质上是在寻找“ @Ignore”类型注释,通过它我可以阻止特定字段的持久化。如何做到这一点?

Answers:


450

@Transient 符合您的需求。


20
但是然后杰克逊在转换为JSON时不会序列化字段...如何解决?
MobileMon

这取决于您的应用程序设计。如果您注释实体类-它适用于所有地方;但是如果您对使用实体的dao进行注释-这是另一回事了。简而言之:当您有多个存储时使用DAO
Andrii Plotnikov '16

在“列表”字段上不起作用。对于集合类型字段,休眠实际上创建了一个新的中间表。有什么解决方法吗?
zulkarnain shah

@MobileMon您可以解决它,检查我的答案stackoverflow.com/a/41850392/3871754
Kamil Nekanowicz '19

@MobileMon最好不要同时将相同的实体用于数据库和API(单一职责)。
JacekŚlimok

126

要忽略某个字段,请用@Transient对其进行注释,这样它就不会被休眠映射。

但是杰克逊在转换为JSON时不会序列化字段。

如果您需要将JPA与JSON混合使用(JPA省略但仍包含在Jackson中),请使用@JsonInclude

@JsonInclude()
@Transient
private String token;

小费:

您还可以使用JsonInclude.Include.NON_NULL并在反序列化期间在JSON时隐藏字段token == null

@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;

3
我正在运行JAX-RS 2.0.1 / Jersey 2.25.1 / Jackson 2.8.7,并且@JsonInclude不需要该堆栈:@Transient字段仍包含在JSON中。(您仍然得到我的投票:该技术本身在其他情况下可能非常有用)。
DKroot

2
我在Spring Boot上做到了
Kamil Nekanowicz

您好,我正在尝试使用此功能,但尚未通过@Transient字段进行序列化
Mohammad

@Mohammad添加注释@JsonInclude()
卡米尔·尼卡

在Spring Boot 2.1.7中进行了尝试,但是没有用。但是您仍然得到我的投票,因为它可能在其他情况下也有效。
Aditya Ekbote

25

要忽略某个字段,请用@Transient对其进行注释,这样它就不会被休眠映射。
资料来源:休眠注释


19

这个答案来得有点晚,但是它完成了回答。

为了避免实体中的字段保留在数据库中,可以使用以下两种机制之一:

@Transient -JPA注释将字段标记为不可持久

Java中的瞬时关键字。当心-使用此关键字,将阻止该字段与Java中的任何序列化机制一起使用。因此,如果必须对字段进行序列化,则最好仅使用 @Transient批注。


1
那我只想忽略get方法的持久性呢?例如:myjparepository.save()将照常保存模型,而myjparepository.find(id)将忽略我想要的字段吗?
xtiger

@xtiger,您可以创建一个自定义查询来存档该功能。这是一个示例链接
Mohale '18

7

根据实体属性类型,有多种解决方案。

基本属性

考虑您有下account表:

帐户表

account表被映射到这样的Account实体:

@Entity(name = "Account")
public class Account {

    @Id
    private Long id;

    @ManyToOne
    private User owner;

    private String iban;

    private long cents;

    private double interestRate;

    private Timestamp createdOn;

    @Transient
    private double dollars;

    @Transient
    private long interestCents;

    @Transient
    private double interestDollars;

    @PostLoad
    private void postLoad() {
        this.dollars = cents / 100D;

        long months = createdOn.toLocalDateTime()
            .until(LocalDateTime.now(), ChronoUnit.MONTHS);
        double interestUnrounded = ( ( interestRate / 100D ) * cents * months ) / 12;
        this.interestCents = BigDecimal.valueOf(interestUnrounded)
            .setScale(0, BigDecimal.ROUND_HALF_EVEN).longValue();

        this.interestDollars = interestCents / 100D;
    }

    //Getters and setters omitted for brevity
}

基本实体属性映射到表列,因此属性喜欢idibancents是基本属性。

但是dollarsinterestCentsinterestDollars计算性能,让您与注释他们@Transient从SELECT,INSERT,UPDATE和DELETE SQL语句中排除。

因此,对于基本属性,您需要使用@Transient以便将给定属性排除在外。

有关计算实体属性的更多详细信息,请参阅本文

社团协会

假设你有以下postpost_comment表:

post和post_comment表

您想要lastestCommentPost实体中的关联映射到PostComment已添加的最新实体。

为此,您可以使用@JoinFormula注释:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinFormula("(" +
        "SELECT pc.id " +
        "FROM post_comment pc " +
        "WHERE pc.post_id = id " +
        "ORDER BY pc.created_on DESC " +
        "LIMIT 1" +
    ")")
    private PostComment latestComment;

    //Getters and setters omitted for brevity
}

提取Post实体时,您可以看到latestComment已获取,但是如果要修改它,则更改将被忽略。

因此,对于关联,您可以使用@JoinFormula忽略写操作,同时仍然允许读取关联。

有关计算关联的更多详细信息,请参阅本文

@MapsId

忽略实体标识符已映射的关联的另一种方法是使用@MapsId

例如,考虑以下一对一表关系:

post和post_details表

PostDetails实体映射是这样的:

@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {

    @Id
    private Long id;

    @Column(name = "created_on")
    private Date createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private Post post;

    public PostDetails() {}

    public PostDetails(String createdBy) {
        createdOn = new Date();
        this.createdBy = createdBy;
    }

    //Getters and setters omitted for brevity
}

请注意,id属性和post关联都映射同一数据库列,即“ post_details主键”列。

为了排除该id属性,@MapsId注释将告诉Hibernate post关联关系负责表的Primary Key列值。

因此,当实体标识符和关联共享同一列时,可以使用@MapsId忽略实体标识符属性,而使用关联。

有关更多信息@MapsId,请查看本文

使用 insertable = false, updatable = false

另一种选择是insertable = false, updatable = false用于要被Hibernate忽略的关联。

例如,我们可以像这样映射先前的一对一关联:

@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {

    @Id
    @Column(name = "post_id")
    private Long id;

    @Column(name = "created_on")
    private Date createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @OneToOne
    @JoinColumn(name = "post_id", insertable = false, updatable = false)
    private Post post;

    //Getters and setters omitted for brevity

    public void setPost(Post post) {
        this.post = post;
        if (post != null) {
            this.id = post.getId();
        }
    }
}

注释的insertableupdatable属性@JoinColumn将指示Hibernate忽略post关联,因为实体标识符负责“ post_id主键”列。


请注意,id属性和发布关联都映射同一数据库列,即post_comment主键列。postpost_details表为例,这是否正确?
David

1
感谢您发现它。我修好了它。
Vlad Mihalcea

3

为了完成上述的答案,我使用XML映射文件必须的情况下既没有@Transient,也没有transient工作...我不得不把瞬时信息的XML文件:

<attributes>
(...)
    <transient name="field" />
</attributes>

2

使用Hibernate 5.2.10,Jersey 2.25.1和Jackson 2.8.9时,以上答案均不适用于我。我终于找到了答案(在某种程度上,它们引用hibernate4module但它工作在5太)在这里。没有Json注释与一起使用@Transient。显然,Jackson2足够“聪明”,可以友好地忽略带有标记的内容,@Transient除非您明确要求不要这样做。关键是添加hibernate5模块(我用来处理其他Hibernate批注)并USE_TRANSIENT_ANNOTATION在Jersey应用程序中禁用该功能:

ObjectMapper jacksonObjectMapper = new ObjectMapper();
Hibernate5Module jacksonHibernateModule = new Hibernate5Module();
jacksonHibernateModule.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
jacksonObjectMapper.registerModule(jacksonHibernateModule);  

这是Hibernate5Module的依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.8.9</version>
</dependency>

在尝试了上述所有其他方法以及其他方法之后, @JsonProperty @JsonInclude @JsonSerialize + @JsonDeserialize mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false));此解决方案终于奏效。谢谢!
Aceonline

1

有时您想要:

  1. 序列化列
  2. 忽略保留列:

采用 @Column(name = "columnName", insertable = false, updatable = false)

一个好的情况是,使用其他列值自动计算出某个列

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.