我基本上正在寻找一个“@Ignore”类型的注释,我可以用它来阻止特定字段被持久化。如何实现这一目标?
答案 0 :(得分:379)
@Transient
符合您的需求。
答案 1 :(得分:80)
要忽略某个字段,请使用@Transient
对其进行注释,以便hibernate不会对其进行映射。
但转换为JSON时, jackson不会序列化字段。
如果您需要将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;
答案 2 :(得分:21)
要忽略某个字段,请使用@Transient
对其进行注释,以便hibernate不会对其进行映射。
来源:Hibernate Annotations。
答案 3 :(得分:15)
这个答案有点晚了,但它完成了回复。
为了避免实体中的字段被保留在DB中,可以使用以下两种机制之一:
@Transient - 将字段标记为不可持久的JPA注释
java中的transient 关键字。注意 - 使用此关键字,将阻止该字段与java中的任何序列化机制一起使用。因此,如果必须序列化该字段,则最好只使用 @Transient 注释。
答案 4 :(得分:10)
有多种解决方案,具体取决于实体属性类型。
请考虑以下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
}
基本实体属性映射到表列,因此id
,iban
,cents
等属性是基本属性。
但是dollars
,interestCents
和interestDollars
是计算属性,因此您用@Transient
注释它们以将它们从SELECT,INSERT,UPDATE和DELETE SQL中排除。声明。
因此,对于基本属性,您需要使用
@Transient
才能排除给定属性的持久性。有关计算的实体属性的更多详细信息,请查看this article。
假设您具有以下post
和post_comment
表:
您要将latestComment
实体中的Post
关联映射到最新添加的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
忽略写操作,同时仍允许读取关联。有关计算的关联的更多详细信息,请查看this article。
忽略实体标识符已映射的关联的另一种方法是使用@MapsId
。
例如,考虑以下一对一表关系:
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
的更多详细信息,请查看this article。
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();
}
}
}
insertable
批注的updatable
和@JoinColumn
属性将指示Hibernate忽略post
关联,因为实体标识符负责post_id
主对象关键列。
答案 5 :(得分:4)
有时候您想:
使用@Column(name = "columnName", insertable = false, updatable = false)
一种好的情况是,使用其他列值自动计算出某列
答案 6 :(得分:2)
为了完成上述答案,我遇到了使用XML映射文件的案例,@Transient
和transient
都没有...
我不得不将瞬态信息放在xml文件中:
<attributes>
(...)
<transient name="field" />
</attributes>
答案 7 :(得分:1)
上述答案都不适用于我使用Hibernate 5.2.10,Jersey 2.25.1和Jackson 2.8.9。我终于找到了答案(有点,他们引用了hibernate4module,但它也适用于5)here。没有任何Json注释与@Transient
一起工作。显然Jackson2是“聪明”的,足以忽略标有@Transient
的东西,除非你明确告诉它不要。关键是添加hibernate5模块(我用它来处理其他Hibernate注释)并禁用我的Jersey应用程序中的USE_TRANSIENT_ANNOTATION
功能:
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>
答案 8 :(得分:1)
使用@Transient使JPA忽略该字段。
但是!杰克逊也不会序列化该字段。要解决,只需添加@JsonProperty
一个例子
@Transient
@JsonProperty
private boolean locked;
答案 9 :(得分:1)
显然,使用 Hibernate5Module,如果使用 ObjectMapper,@Transient 将不会被序列化。删除将使其工作。
import javax.persistence.Transient;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TransientFieldTest {
@Test
public void Print_Json() throws JsonProcessingException {
ObjectMapper objectEntityMapper = new ObjectMapper();
//objectEntityMapper.registerModule(new Hibernate5Module());
objectEntityMapper.setSerializationInclusion(Include.NON_NULL);
log.info("object: {}", objectEntityMapper.writeValueAsString( //
SampleTransient.builder()
.id("id")
.transientField("transientField")
.build()));
}
@Getter
@Setter
@Builder
private static class SampleTransient {
private String id;
@Transient
private String transientField;
private String nullField;
}
}