Kalıcılık sırasında bir JPA alanını yok saymanın en kolay yolu nedir?


281

Temelde ben belirli bir alan kalıcı olmasını engelleyebilir bir "@Ignore" türü ek açıklama arıyorum. Bu nasıl başarılabilir?

Yanıtlar:


450

@Transient ihtiyaçlarınızı karşılar.


20
Ama sonra jackson JSON dönüştürürken alan seri hale getirmez ... nasıl çözmek?
— MobileMon

Bu, uygulama tasarımınıza bağlıdır. varlık sınıfınıza ek açıklama eklediğinizde - her yerde geçerlidir; ama varlık kullanan dao'ya açıklama yaparsanız - bu başka bir hikaye. Kısacası: birden fazla depolamanız olduğunda
— DAO'yu

Liste alanlarında çalışmaz. Koleksiyon türü alanları için hazırda bekletme modu aslında yeni bir ara tablo oluşturur. Bunun için bir çözüm var mı?
— zulkarnain shah

@MobileMon Çözebilirsin, cevabımı kontrol et stackoverflow.com/a/41850392/3871754
— Kamil Nekanowicz

@MobileMon Tercihen aynı varlığı hem veritabanı hem de API amaçları için kullanmamalısınız (tek sorumluluk).
— Jacek Ślimok

127

Bir alanı yok saymak için, @Transienthazırda bekletme modu ile eşlenmeyecek şekilde ek açıklama ekleyin.

ancak jackson JSON'a dönüştürürken alanı serileştirmez .

JPA'yı JSON ile karıştırmanız gerekiyorsa (JPA tarafından atlayın, ancak yine de Jackson'a ekleyin) kullanın @JsonInclude:

@JsonInclude()
@Transient
private String token;

İPUCU:

Ayrıca, aşağıdaki durumlarda seriyi kaldırma işlemi sırasında JsonInclude.Include.NON_NULL kullanabilir ve JSON'daki alanları gizleyebilirsiniz token == null:

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

3
JAX-RS 2.0.1 / Jersey 2.25.1 / Jackson 2.8.7 kullanıyorum ve bu yığın @JsonIncludeile gerekli değildir: @Transientalanlar hala JSON'a dahildir. (Hala benim oyumu aldım: tekniğin kendisi diğer durumlarda çok yararlı olabilir).
— DKroot

2
Spring Boot üzerinde yaptım
— Kamil Nekanowicz

merhaba, bunu kullanmaya çalışıyorum, ama @Transient alanı ile seri hale getirilmiyor
— Mohammad

@Mohammad ek açıklama ekle @JsonInclude ()
— Kamil Nekanowicz

Bunu Spring Boot 2.1.7'de denedim ama işe yaramadı. Ama yine de oyumu alıyorsunuz çünkü başka senaryolarda da işe yarayabilir.
— Aditya Ekbote


19

Bu cevap biraz geç gelir, ancak cevabı tamamlar.

Bir kuruluştaki bir alanın DB'de kalıcı olmasını önlemek için, iki mekanizmadan biri kullanılabilir:

@Transient - JPA ek açıklaması bir alanı kalıcı olarak işaretliyor

geçici anahtar kelime. Dikkat - bu anahtar kelimenin kullanılması, alanın java herhangi bir serileştirme mekanizması ile kullanılmasını önleyecektir. Bu nedenle, alanın serileştirilmesi gerekiyorsa, yalnızca @Transient ek açıklamasınıkullanmanız daha iyi olur.


1
nasıl olsun sadece yöntemi kalıcılığını yoksaymak istiyorum ?. Örneğin: myjparepository.save () modeli her zamanki gibi kaydeder ve myjparepository.find (id) istediğim alanı yoksayar mı?
— xtiger

@xtiger bu işlevselliği arşivlemek için özel bir sorgu oluşturabilirsiniz. İşte bir örnek bağlantı
— Mohale

7

Obje öznitelik türüne bağlı olarak birden fazla çözüm vardır.

Temel özellikler

Aşağıdaki accounttabloya sahip olduğunuzu düşünün :

Hesap tablosu

accountTablo eşleştirilir Accountböyle varlık:

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

Temel varlık nitelikleri özellikleri seversin, tablo sütunları eşlenir id, iban, centstemel özelliklerdir.

Ama dollars, interestCentsve interestDollarssen onları açıklama yüzden, özellikler hesaplanır @TransientSELECT, INSERT, UPDATE ve DELETE SQL ifadelerinin dışında tutmak.

Bu nedenle, temel özellikler için, @Transientbelirli bir mülkün kalıcı olmasını engellemek için kullanmanız gerekir .

Hesaplanan varlık özellikleri hakkında daha fazla bilgi için bu makaleye göz atın .

Dernekler

Aşağıdakilere sahip olduğunuzu varsayarsak post ve post_commenttablolara :

Yayın ve yayın sonrası tabloları

Varlıktaki lastestCommentilişkilendirmeyi eklenen Posten son PostCommentvarlıkla eşleştirmek istiyorsunuz .

Bunu yapmak için, @JoinFormula ek açıklamayı :

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

Getirirken PostlatestComment , getirildiğini görebilirsiniz , ancak değiştirmek isterseniz, değişiklik yok sayılır.

Böylece, ilişkilendirmeler için, ilişkilendirmeyi @JoinFormulaokumaya izin verirken yazma işlemlerini yoksayabilirsiniz.

Hesaplanan dernekler hakkında daha fazla bilgi için bu makaleye göz atın .

@MapsId

Varlık tanımlayıcısı tarafından önceden eşleştirilen ilişkilendirmeleri yok saymanın başka bir yolu da @MapsId .

Örneğin, aşağıdaki bire bir tablo ilişkisini düşünün:

Yazı ve yazı_detayları tabloları

PostDetailsVarlık böyle eşleştirilmiş:

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

Hem idözniteliğin hem de postilişkilendirmenin aynı veritabanı sütununu eşlediğine dikkat edin;post_details Birincil Anahtar sütunu eşlediğine dikkat edin.

idÖzniteliği hariç tutmak için @MapsIdek açıklama, Hazırda Beklet'e postilişkilendirmenin Birincil Anahtar sütun değeri tablosuyla ilgilendiğini bildirir .

Bu nedenle, varlık tanımlayıcısı ve ilişkilendirme aynı sütunu paylaştığında @MapsId, varlık tanımlayıcısı niteliğini yok saymak ve bunun yerine ilişkilendirmeyi kullanabilirsiniz.

Hakkında daha fazla bilgi için bu makaleye@MapsId göz atın .

kullanma insertable = false, updatable = false

Başka bir seçenek, insertable = false, updatable = falseHazırda Bekletme tarafından yoksayılmasını istediğiniz ilişkilendirme için kullanmaktır .

Örneğin, önceki bire bir ilişkilendirmeyi şu şekilde eşleştirebiliriz:

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

insertableVe updatablenitelikleri @JoinColumnaçıklama görmezden Hibernate talimat verir postilgilenir tanımlayıcı varlık beri dernek post_idBirincil Anahtar sütununda.


Hem id özelliğinin hem de post ilişkilendirmesinin, post_comment Birincil Anahtar sütunu olan aynı veritabanı sütununu eşlediğine dikkat edin. Bu örnek postve post_detailstablolar bağlamında doğru mu?
— David

1
Tespit ettiğiniz için teşekkürler. Onardım.
— Vlad Mihalcea

3

Yukarıdaki cevapları tamamlamak için, ne ne ne @Transientde transientçalıştı bir XML eşleme dosyası kullanarak dava vardı ... Ben xml dosyasına geçici bilgi koymak zorunda kaldı:

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

2

Yukarıdaki cevapların hiçbiri Hibernate 5.2.10, Jersey 2.25.1 ve Jackson 2.8.9 kullanarak benim için işe yaramadı. Sonunda cevabı buldum (bir çeşit, hibernate4module'ye referans veriyorlar, ancak 5 için de çalışıyor) burada . Json ek açıklamalarının hiçbiri hiç işe yaramadı @Transient. Görünüşe göre Jackson2, @Transientaçıkça söylemediğiniz sürece işaretlenen şeyleri göz ardı edecek kadar 'akıllı' . Anahtar, hibernate5 modülünü (diğer Hibernate ek açıklamalarıyla uğraşmak için kullandığım) eklemek ve USE_TRANSIENT_ANNOTATIONJersey Uygulamamdaki özelliği devre dışı bırakmaktı :

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

Hibernate5Module bağımlılığı:

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

Yukarıda bahsedilen diğer yöntemlerin hepsini denedikten sonra @JsonProperty @JsonInclude @JsonSerialize + @JsonDeserialize mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false));bu çözüm nihayet işe yaradı. Teşekkürler!
— Ekim'de Aceonline

1

Bazen şunları yapmak istersiniz:

  1. Bir sütunu seri hale getirme
  2. Sütunun kalıcı olmasını yoksay:

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

İyi bir senaryo, belirli bir sütunun diğer sütun değerleri kullanılarak otomatik olarak hesaplanmasıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.