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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1281952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 07:46:35  来源:igfitidea点击:

What is the easiest way to ignore a JPA field during persistence?

javadatabasehibernatejpa

提问by m2o

I'm essentially looking for a "@Ignore" type annotation with which I can stop a particular field from being persisted. How can this be achieved?

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

采纳答案by cletus

@Transientcomplies with your needs.

@Transient符合您的需求。

回答by Jonathan

To ignore a field, annotate it with @Transientso it will not be mapped by hibernate.
Source: Hibernate Annotations.

要忽略字段,请对其进行注释,@Transient使其不会被休眠映射。
来源:Hibernate 注释

回答by Olimpiu POP

This answer comes a little late, but it completes the response.

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

In order to avoid a field from an entity to be persisted in DB one can use one of the two mechanisms:

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

@Transient- the JPA annotation marking a field as not persistable

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

transientkeyword in java. Beware - using this keyword, will prevent the field to be used with any serialization mechanism from java. So, if the field must be serialized you'd better use just the @Transientannotation.

java中的transient关键字。当心 - 使用此关键字将阻止该字段与来自 java 的任何序列化机制一起使用。因此,如果字段必须被序列化,您最好只使用@Transient注释。

回答by Vinze

To complete the above answers, I had the case using an XML mapping file where neither the @Transientnor transientworked... I had to put the transient information in the xml file:

为了完成上述答案,我有一个使用 XML 映射文件的案例,其中既不工作@Transient也不transient工作......我不得不将瞬态信息放在 xml 文件中:

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

回答by Kamil Nekanowicz

To ignore a field, annotate it with @Transientso it will not be mapped by hibernate.

要忽略字段,请对其进行注释,@Transient使其不会被休眠映射。

but then Hymanson will not serializethe field when converting to JSON.

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

If you need mix JPA with JSON(omit by JPA but still include in Hymanson) use @JsonInclude:

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

@JsonInclude()
@Transient
private String token;

TIP:

提示:

You can also use JsonInclude.Include.NON_NULLand hide fields in JSON during deserialization when token == null:

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

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

回答by Hodglem

None of the above answers worked for me using Hibernate 5.2.10, Jersey 2.25.1 and Hymanson 2.8.9. I finally found the answer (sort of, they reference hibernate4module but it works for 5 too) here. None of the Json annotations worked at all with @Transient. Apparently Hymanson2 is 'smart' enough to kindly ignore stuff marked with @Transientunless you explicitly tell it not to. The key was to add the hibernate5 module (which I was using to deal with other Hibernate annotations) and disable the USE_TRANSIENT_ANNOTATIONfeature in my Jersey Application:

使用 Hibernate 5.2.10、Jersey 2.25.1 和 Hymanson 2.8.9,上述答案都不适合我。我终于找到了答案(在某种程度上,它们引用hibernate4module但它工作在5太)在这里。没有任何 Json 注释与@Transient. 显然,Hymanson2 足够“聪明”,可以忽略标有 的内容,@Transient除非您明确告诉它不要。关键是添加 hibernate5 模块(我用来处理其他 Hibernate 注释)并USE_TRANSIENT_ANNOTATION在我的 Jersey 应用程序中禁用该功能:

ObjectMapper HymansonObjectMapper = new ObjectMapper();
Hibernate5Module HymansonHibernateModule = new Hibernate5Module();
HymansonHibernateModule.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
HymansonObjectMapper.registerModule(HymansonHibernateModule);  

Here is the dependency for the Hibernate5Module:

这是 Hibernate5Module 的依赖项:

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

回答by Vlad Mihalcea

There are multiple solutions depending on the entity attribute type.

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

Basic attributes

基本属性

Consider you have the following accounttable:

考虑您有下account表:

The account table

账户表

The accounttable is mapped to the Accountentity like this:

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
}

The basic entity attributes are mapped to table columns, so properties like id, iban, centsare basic attributes.

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

But the dollars, interestCents, and interestDollarsare computed properties, so you annotate them with @Transientto exclude them from SELECT, INSERT, UPDATE, and DELETE SQL statements.

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

So, for basic attributes, you need to use @Transientin order to exclude a given property from being persisted.

For more details about computed entity attributes, check out this article.

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

有关计算实体属性的更多详细信息,请查看这篇文章

Associations

协会

Assuming you have the following postand post_commenttables:

假设您有以下postpost_comment表格:

The post and post_comment tables

post 和 post_comment 表

You want to map the lastestCommentassociation in the Postentity to the latest PostCommententity that was added.

您希望lastestCommentPost实体中的关联映射到PostComment添加的最新实体。

To do that, you can use the @JoinFormulaannotation:

为此,您可以使用@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
}

When fetching the Postentity, you can see that the latestCommentis fetched, but if you want to modify it, the change is going to be ignored.

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

So, for associations, you can use @JoinFormulato ignore the write operations while still allowing reading the association.

For more details about computed associations, check out this article.

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

有关计算关联的更多详细信息,请查看这篇文章

@MapsId

@MapsId

Another way to ignore associations that are already mapped by the entity identifier is to use @MapsId.

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

For instance, consider the following one-to-one table relationship:

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

The post and post_details tables

post 和 post_details 表

The PostDetailsentity is mapped like this:

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
}

Notice that both the idattribute and the postassociation map the same database column, which is the post_detailsPrimary Key column.

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

To exclude the idattribute, the @MapsIdannotation will tell Hibernate that the postassociation takes care of the table Primary Key column value.

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

So, when the entity identifier and an association share the same column, you can use @MapsIdto ignore the entity identifier attribute and use the association instead.

For more details about @MapsId, check out this article.

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

有关更多详细信息@MapsId,请查看这篇文章

Using insertable = false, updatable = false

使用 insertable = false, updatable = false

Another option is to use insertable = false, updatable = falsefor the association which you want to be ignored by Hibernate.

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

For instance, we can map the previous one-to-one association like this:

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

@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();
        }
    }
}

The insertableand updatableattributes of the @JoinColumnannotation will instruct Hibernate to ignore the postassociation since the entity identifier takes care of the post_idPrimary Key column.

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

回答by Obothlale

Sometimes you want to:

有时你想:

  1. Serialize a column
  2. Ignore column from being persisted:
  1. 序列化一列
  2. 忽略被持久化的列:

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

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

A good scenario is when a certain column is automatically calculated by using other column values

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