Was ist der einfachste Weg, ein JPA-Feld während der Persistenz zu ignorieren?

281

Ich suche im Wesentlichen nach einer Annotation vom Typ "@Ignore", mit der ich verhindern kann, dass ein bestimmtes Feld beibehalten wird. Wie kann dies erreicht werden?

m2o
quelle

Antworten:

450

@Transient entspricht Ihren Bedürfnissen.

Cletus
quelle
20
Aber dann wird Jackson das Feld bei der Konvertierung in JSON nicht serialisieren ... wie löst man das?
MobileMon
Das hängt von Ihrem App-Design ab. Wenn Sie Ihre Entitätsklasse mit Anmerkungen versehen, gilt dies überall. Aber wenn Sie dao, die Entität verwenden, anotieren, ist es eine andere Geschichte. Kurz gesagt: Verwenden Sie DAO, wenn Sie mehrere Speicher haben
Andrii Plotnikov
Funktioniert nicht in Listenfeldern. Für Felder vom Typ Sammlung erstellt der Ruhezustand tatsächlich eine neue Zwischentabelle. Irgendeine Problemumgehung dafür?
Zulkarnain Shah
@ MobileMon Sie können es lösen, überprüfen Sie meine Antwort stackoverflow.com/a/41850392/3871754
Kamil Nekanowicz
@MobileMon Vorzugsweise sollten Sie nicht dieselbe Entität sowohl für Datenbank- als auch für API-Zwecke verwenden (Einzelverantwortung).
Jacek Ślimok
126

Um ein Feld zu ignorieren, kommentieren Sie es mit, @Transientdamit es nicht im Ruhezustand zugeordnet wird.

Aber dann serialisiert Jackson das Feld bei der Konvertierung in JSON nicht.

Wenn Sie JPA mit JSON mischen müssen (von JPA weglassen, aber immer noch in Jackson enthalten), verwenden Sie @JsonInclude:

@JsonInclude()
@Transient
private String token;

TRINKGELD:

Sie können auch JsonInclude.Include.NON_NULL verwenden und Felder in JSON während der Deserialisierung ausblenden, wenn token == null:

@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;
Kamil Nekanowicz
quelle
3
Ich verwende JAX-RS 2.0.1 / Jersey 2.25.1 / Jackson 2.8.7 und mit diesem Stack @JsonIncludeist dies nicht erforderlich: @TransientFelder sind weiterhin in JSON enthalten. (Sie haben immer noch meine Stimme erhalten: Die Technik selbst könnte unter anderen Umständen sehr nützlich sein).
DKroot
2
Ich habe es auf Spring Boot gemacht
Kamil Nekanowicz
Hallo, ich versuche dies zu verwenden, aber es wird nicht mit @Transient Feld serialisiert
Mohammad
@Mohammad Anmerkung hinzufügen @JsonInclude ()
Kamil Nekanowicz
Versuchte dies in Spring Boot 2.1.7, funktionierte aber nicht. Aber trotzdem bekommst du meine Stimme, weil es in anderen Szenarien funktionieren kann.
Aditya Ekbote
25

Um ein Feld zu ignorieren, kommentieren Sie es mit, @Transientdamit es nicht im Ruhezustand zugeordnet wird.
Quelle: Anmerkungen zum Ruhezustand .

Jonathan
quelle
19

Diese Antwort kommt etwas spät, vervollständigt aber die Antwort.

Um zu vermeiden, dass ein Feld einer Entität in der Datenbank beibehalten wird, kann einer der beiden Mechanismen verwendet werden:

@Transient - Die JPA-Annotation, die ein Feld als nicht dauerhaft markiert

vorübergehendes Schlüsselwort in Java. Achtung: Wenn Sie dieses Schlüsselwort verwenden, wird verhindert, dass das Feld mit einem Serialisierungsmechanismus von Java verwendet wird. Wenn das Feld also serialisiert werden muss, verwenden Sie besser nur dieAnnotation @Transient .

Olimpiu POP
quelle
1
Wie wäre es, wenn ich nur die Persistenz der get-Methode ignorieren möchte? Beispiel: myjparepository.save () speichert das Modell wie gewohnt und myjparepository.find (id) ignoriert das gewünschte Feld?
xtiger
@xtiger Sie können eine benutzerdefinierte Abfrage erstellen, um diese Funktionalität zu archivieren. Hier ist ein Beispiel Link
Mohale
7

Abhängig vom Entitätsattributtyp gibt es mehrere Lösungen.

Grundlegende Attribute

Angenommen, Sie haben die folgende accountTabelle:

Die Kontotabelle

Die accountTabelle wird der AccountEntität wie folgt zugeordnet :

@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
}

Die Grundeinheit Attribute werden in Tabellenspalten zugeordnet, so Eigenschaften wie id, iban, centssind grundlegende Attribute.

Aber die dollars, interestCentsund interestDollarsEigenschaften berechnet werden , so dass Sie sie mit Anmerkungen versehen mit @Transientauszuschließen sie von SELECT, INSERT, UPDATE und DELETE SQL - Anweisungen.

Für grundlegende Attribute müssen Sie also verwenden @Transient, um eine bestimmte Eigenschaft vom Fortbestehen auszuschließen.

Weitere Informationen zu berechneten Entitätsattributen finden Sie in diesem Artikel .

Verbände

Angenommen, Sie haben Folgendes postund post_commentTabellen:

Die Tabellen post und post_comment

Sie möchten die lastestCommentZuordnung in der PostEntität der zuletzt PostCommenthinzugefügten Entität zuordnen.

Dazu können Sie die @JoinFormulaAnmerkung verwenden:

@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
}

Beim Abrufen der PostEntität können Sie sehen, dass die Entität latestCommentabgerufen wird. Wenn Sie sie jedoch ändern möchten, wird die Änderung ignoriert.

Bei Zuordnungen können Sie also @JoinFormuladie Schreibvorgänge ignorieren, während Sie das Lesen der Zuordnung weiterhin zulassen.

Weitere Informationen zu berechneten Zuordnungen finden Sie in diesem Artikel .

@MapsId

Eine andere Möglichkeit, Assoziationen zu ignorieren, die bereits von der Entitätskennung zugeordnet wurden, ist die Verwendung @MapsId.

Betrachten Sie beispielsweise die folgende Eins-zu-Eins-Tabellenbeziehung:

Die Tabellen post und post_details

Die PostDetailsEntität wird wie folgt zugeordnet:

@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
}

Beachten Sie, dass sowohl das idAttribut als auch die postZuordnung dieselbe Datenbankspalte zuordnen, die die post_detailsPrimärschlüsselspalte ist.

Um das idAttribut auszuschließen , @MapsIdteilt die Annotation Hibernate mit, dass sich die postZuordnung um den Spaltenwert der Tabelle Primärschlüssel kümmert.

Wenn also die Entitätskennung und eine Zuordnung dieselbe Spalte verwenden, können Sie @MapsIddas Entitätskennungsattribut ignorieren und stattdessen die Zuordnung verwenden.

Weitere Informationen zu @MapsIdfinden Sie in diesem Artikel .

Verwenden von insertable = false, updatable = false

Eine andere Option ist die Verwendung insertable = false, updatable = falsefür die Zuordnung, die vom Ruhezustand ignoriert werden soll.

Zum Beispiel können wir die vorherige Eins-zu-Eins-Zuordnung wie folgt abbilden:

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

Die Attribute insertableund updatableder @JoinColumnAnnotation weisen Hibernate an, die postZuordnung zu ignorieren , da sich die Entitätskennung um die post_idSpalte Primärschlüssel kümmert .

Vlad Mihalcea
quelle
Beachten Sie, dass sowohl das ID-Attribut als auch die Post-Zuordnung dieselbe Datenbankspalte zuordnen, bei der es sich um die Primärschlüsselspalte post_comment handelt. Ist dies im Kontext von postund post_detailsTabellen als Beispiel korrekt ?
David
1
Danke, dass du es entdeckt hast. Ich habe es repariert.
Vlad Mihalcea
3

Um die obigen Antworten zu vervollständigen, hatte ich den Fall, dass eine XML-Zuordnungsdatei verwendet wurde, in der weder die @Transientnoch transientfunktionierte ... Ich musste die vorübergehenden Informationen in die XML-Datei einfügen:

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

Keine der oben genannten Antworten hat bei mir mit Hibernate 5.2.10, Jersey 2.25.1 und Jackson 2.8.9 funktioniert. Ich fand schließlich die Antwort ( eine Art Bezug sie hibernate4module aber es funktioniert für 5 auch) hier . Keine der Json-Anmerkungen funktionierte überhaupt mit @Transient. Anscheinend ist Jackson2 "klug" genug, um Dinge zu ignorieren, die mit gekennzeichnet sind, es @Transientsei denn, Sie sagen ausdrücklich, dass dies nicht der Fall ist . Der Schlüssel bestand darin, das Hibernate5-Modul hinzuzufügen (mit dem ich andere Hibernate-Anmerkungen bearbeitet habe) und die USE_TRANSIENT_ANNOTATIONFunktion in meiner Jersey-Anwendung zu deaktivieren :

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

Hier ist die Abhängigkeit für das Hibernate5Module:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.8.9</version>
</dependency>
Hodglem
quelle
Nachdem alle anderen oben genannten und andere Methoden ausprobiert wurden, @JsonProperty @JsonInclude @JsonSerialize + @JsonDeserialize mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false));funktionierte diese Lösung schließlich. Vielen Dank!
Aceonline
1

Manchmal möchten Sie:

  1. Serialisieren Sie eine Spalte
  2. Ignorieren Sie das Fortbestehen der Spalte:

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

Ein gutes Szenario ist, wenn eine bestimmte Spalte automatisch unter Verwendung anderer Spaltenwerte berechnet wird

Obothlale
quelle