Apa cara termudah untuk mengabaikan bidang JPA selama kegigihan?

281

Saya pada dasarnya mencari anotasi jenis "@Ignore" yang dengannya saya dapat menghentikan bidang tertentu agar tidak bertahan. Bagaimana ini bisa dicapai?

m2o
sumber

Jawaban:

450

@Transient sesuai dengan kebutuhan Anda.

cletus
sumber
20
Tapi kemudian jackson tidak akan membuat cerita bersambung lapangan ketika mengkonversi ke JSON ... bagaimana cara mengatasinya?
MobileMon
itu tergantung pada keinginan aplikasi Anda. jika Anda membubuhi keterangan kelas entitas Anda - itu berlaku di mana-mana; tetapi jika Anda memberi anotasi dao yang menggunakan entitas - itu cerita lain. singkatnya: gunakan DAO ketika Anda memiliki banyak penyimpanan
Andrii Plotnikov
Tidak berfungsi di bidang Daftar. Untuk bidang tipe Koleksi, hibernasi sebenarnya membuat tabel perantara baru. Ada solusi untuk itu?
zulkarnain shah
@MobileMon Anda dapat menyelesaikannya, periksa jawaban saya stackoverflow.com/a/41850392/3871754
Kamil Nekanowicz
@MobileMon Sebaiknya Anda tidak menggunakan entitas yang sama untuk tujuan basis data dan API (satu tanggung jawab).
Jacek Ślimok
127

Untuk mengabaikan bidang, beri keterangan dengan @Transientsehingga tidak akan dipetakan oleh hibernate.

tapi kemudian jackson tidak akan membuat cerita bersambung lapangan ketika mengkonversi ke JSON.

Jika Anda perlu mencampur JPA dengan JSON (dihilangkan oleh JPA tetapi masih termasuk dalam Jackson) gunakan @JsonInclude:

@JsonInclude()
@Transient
private String token;

TIP:

Anda juga dapat menggunakan JsonInclude.Include.NON_NULL dan sembunyikan bidang di JSON selama deserialisasi ketika token == null:

@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;
Kamil Nekanowicz
sumber
3
Saya menjalankan JAX-RS 2.0.1 / Jersey 2.25.1 / Jackson 2.8.7 dan dengan tumpukan @JsonIncludeitu tidak perlu: @Transientbidang masih termasuk dalam JSON. (Anda masih mendapatkan suara saya: teknik itu sendiri mungkin sangat berguna dalam keadaan lain).
DKroot
2
Saya melakukannya di Spring Boot
Kamil Nekanowicz
hai, saya mencoba menggunakan ini, tetapi tidak mendapatkan serial dengan bidang @Transient
Mohammad
@Mohammad menambahkan anotasi @JsonInclude ()
Kamil Nekanowicz
Mencoba ini di Spring Boot 2.1.7 tetapi tidak berhasil. Tetapi Anda tetap mendapatkan suara saya karena ini dapat bekerja dalam skenario lain.
Aditya Ekbote
25

Untuk mengabaikan bidang, beri keterangan dengan @Transientsehingga tidak akan dipetakan oleh hibernate.
Sumber: Anotasi Hibernasi .

Jonathan
sumber
19

Jawaban ini datang agak terlambat, tetapi melengkapi respons.

Untuk menghindari bidang dari entitas yang akan bertahan dalam DB seseorang dapat menggunakan salah satu dari dua mekanisme:

@Transient - anotasi JPA menandai bidang sebagai tidak dapat bertahan

kata kunci sementara di java. Hati-hati - menggunakan kata kunci ini, akan mencegah bidang untuk digunakan dengan mekanisme serialisasi apa pun dari java. Jadi, jika bidang harus serial, Anda sebaiknya menggunakananotasi @Transient saja .

Olimpiu POP
sumber
1
bagaimana kalau saya hanya ingin mengabaikan kegigihan pada metode get? Sebagai contoh: myjparepository.save () akan menyimpan model seperti biasa, dan myjparepository.find (id) akan mengabaikan bidang yang saya inginkan?
xtiger
@xtiger Anda dapat membuat kueri khusus untuk mengarsipkan fungsionalitas itu. Berikut ini contoh tautan
Mohale
7

Ada beberapa solusi tergantung pada tipe atribut entitas.

Atribut dasar

Pertimbangkan Anda memiliki accounttabel berikut :

Tabel akun

The accounttabel dipetakan ke Accountentitas seperti ini:

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

Atribut entitas dasar dipetakan ke kolom tabel, sehingga sifat suka id, iban, centsadalah atribut dasar.

Tapi dollars, interestCents, dan interestDollarsyang sifat dihitung, sehingga Anda menjelaskannya dengan @Transientmengecualikan mereka dari SELECT, INSERT, UPDATE, dan pernyataan SQL DELETE.

Jadi, untuk atribut dasar, Anda harus menggunakan @Transientuntuk mengecualikan properti yang diberikan agar tidak tetap ada.

Untuk detail lebih lanjut tentang atribut entitas yang dihitung, lihat artikel ini .

Asosiasi

Dengan asumsi Anda memiliki yang berikut postdan post_commenttabel:

Tabel post dan post_comment

Anda ingin memetakan lastestCommentasosiasi di Postentitas ke yang terbaruPostComment entitas yang ditambahkan.

Untuk melakukannya, Anda dapat menggunakan @JoinFormulaanotasi:

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

Saat mengambil Postentitas, Anda dapat melihat bahwa latestCommentitu diambil, tetapi jika Anda ingin memodifikasinya, perubahan akan diabaikan.

Jadi, untuk asosiasi, Anda dapat menggunakan @JoinFormulauntuk mengabaikan operasi penulisan sambil tetap membolehkan membaca asosiasi.

Untuk detail lebih lanjut tentang asosiasi yang dihitung, lihat artikel ini .

@MapsId

Cara lain untuk mengabaikan asosiasi yang sudah dipetakan oleh pengenal entitas adalah menggunakan @MapsId.

Misalnya, pertimbangkan hubungan tabel satu-ke-satu berikut:

Tabel post dan post_details

The PostDetailsentitas dipetakan seperti ini:

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

Perhatikan bahwa idatribut dan postasosiasi memetakan kolom basis data yang sama, yaitupost_details kolom Kunci Utama.

Untuk mengecualikan idatribut, @MapsIdanotasi akan memberi tahu Hibernate bahwa postasosiasi menangani tabel nilai kolom Primary Key.

Jadi, ketika pengidentifikasi entitas dan asosiasi berbagi kolom yang sama, Anda bisa menggunakan @MapsIduntuk mengabaikan atribut entitas pengidentifikasi dan menggunakan asosiasi itu.

Untuk detail lebih lanjut @MapsId, lihat artikel ini .

Menggunakan insertable = false, updatable = false

Opsi lain adalah menggunakan insertable = false, updatable = falseasosiasi yang ingin Anda abaikan oleh Hibernate.

Misalnya, kita dapat memetakan asosiasi satu-ke-satu sebelumnya seperti ini:

@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 insertabledan updatableatribut @JoinColumnpenjelasan akan menginstruksikan Hibernate untuk mengabaikan postasosiasi sejak entitas identifier mengurus post_idkolom Primary Key.

Vlad Mihalcea
sumber
Perhatikan bahwa atribut id dan asosiasi posting memetakan kolom basis data yang sama, yang merupakan kolom kunci utama post_comment. Apakah ini benar dalam konteks postdan post_detailstabel sebagai contoh?
David
1
Terima kasih telah melihatnya. Aku telah memperbaikinya.
Vlad Mihalcea
3

Untuk menyelesaikan jawaban di atas, saya memiliki kasing menggunakan file pemetaan XML di mana tidak ada @Transientatau transientbekerja ... Saya harus memasukkan informasi sementara di file xml:

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

Tidak ada jawaban di atas yang berfungsi untuk saya menggunakan Hibernate 5.2.10, Jersey 2.25.1 dan Jackson 2.8.9. Saya akhirnya menemukan jawabannya (semacam, mereka referensi hibernate4module tetapi berfungsi untuk 5 juga) di sini . Tak satu pun dari anotasi Json bekerja sama sekali @Transient. Rupanya Jackson2 'cukup' cukup baik untuk mengabaikan hal-hal yang ditandai @Transientkecuali jika Anda secara eksplisit mengatakannya untuk tidak melakukannya. Kuncinya adalah menambahkan modul hibernate5 (yang saya gunakan untuk berurusan dengan anotasi Hibernate lainnya) dan menonaktifkan USE_TRANSIENT_ANNOTATIONfitur di Aplikasi Jersey saya:

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

Berikut adalah ketergantungan untuk Hibernate5Module:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.8.9</version>
</dependency>
Hodglem
sumber
Setelah mencoba setiap metode lain yang disebutkan di atas dan yang lainnya @JsonProperty @JsonInclude @JsonSerialize + @JsonDeserialize mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false));, solusi ini akhirnya berhasil. Terima kasih!
Aceonline
1

Terkadang Anda ingin:

  1. Buat serial kolom
  2. Abaikan kolom agar tidak bertahan:

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

Skenario yang baik adalah ketika kolom tertentu secara otomatis dihitung dengan menggunakan nilai kolom lainnya

Obothlale
sumber