JPA在持久化期间忽略字段的最快方法?

m2o*_*m2o 254 java database hibernate jpa

我基本上正在寻找一个"@Ignore"类型的注释,我可以用它来阻止特定字段被持久化.怎么能实现这一目标?

cle*_*tus 406

@Transient 符合您的需求.

  • 但是当转换为JSON时,杰克逊不会将字段序列化......如何解决? (17认同)

Kam*_*icz 102

要忽略一个字段,请用@Transient它来注释它,这样它就不会被hibernate映射.

但是当转换为JSON时,jackson不会序列化该字段.

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

@JsonInclude()
@Transient
private String token;
Run Code Online (Sandbox Code Playgroud)

小费:

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

@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;
Run Code Online (Sandbox Code Playgroud)

  • 我正在运行JAX-RS 2.0.1/Jersey 2.25.1/Jackson 2.8.7并且没有必要使用那个堆栈`@JsonInclude`:`@ Transient`字段仍然包含在JSON中.(你仍然得到我的投票:技术本身在其他情况下可能非常有用). (3认同)
  • 我是在 Spring Boot 上做的 (2认同)
  • 仅当 jackson-datatype-hibernate 模块位于类路径上并注册到 ObjectMapper 时,才会排除“@Transient”字段,这可能是使用 Jackson 和 Hibernate 的 Spring Boot 应用程序的默认设置,以及为什么还要设置“@JsonInclude”对于其他人来说是可选的。 (2认同)

小智 22

要忽略一个字段,请用@Transient它来注释它,这样它就不会被hibernate映射.
来源:Hibernate Annotations.


Oli*_*POP 16

这个答案有点晚了,但它完成了回复.

为了避免实体中的字段持久存储在DB中,可以使用以下两种机制之一:

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

java中的 transient关键字.注意 - 使用此关键字,将阻止该字段与java中的任何序列化机制一起使用.因此,如果必须对字段进行序列化,则最好只使用 @Transient注释.


Vla*_*cea 12

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

基本属性

考虑您有下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
}
Run Code Online (Sandbox Code Playgroud)

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

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

因此,对于基本属性,您需要使用@Transient以从持久化中排除给定的属性。

协会

假设您有以下postpost_comment表格:

post 和 post_comment 表

您希望latestCommentPost实体中的关联映射到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
}
Run Code Online (Sandbox Code Playgroud)

在获取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
}
Run Code Online (Sandbox Code Playgroud)

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

为了排除该id属性,@MapsId注解会告诉 Hibernatepost关联负责处理表的主键列值。

因此,当实体标识符和关联共享同一列时,您可以使用@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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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


小智 9

有时你想:

  1. 序列化一列
  2. 忽略被持久化的列:

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

一个很好的场景是当某个列使用其他列值自动计算时


And*_*rey 9

使用 @Transient 使 JPA 忽略该字段。

但!杰克逊也不会连载该领域。要解决只需添加@JsonProperty

一个例子

@Transient
@JsonProperty
private boolean locked;
Run Code Online (Sandbox Code Playgroud)