ฉันกำลังมองหาคำอธิบายประกอบแบบ "@Ignore" เป็นหลักซึ่งฉันสามารถหยุดฟิลด์ใดฟิลด์หนึ่งจากการถูกยืนยันได้ จะประสบความสำเร็จได้อย่างไร?
ฉันกำลังมองหาคำอธิบายประกอบแบบ "@Ignore" เป็นหลักซึ่งฉันสามารถหยุดฟิลด์ใดฟิลด์หนึ่งจากการถูกยืนยันได้ จะประสบความสำเร็จได้อย่างไร?
คำตอบ:
@Transient
สอดคล้องกับความต้องการของคุณ
หากต้องการละเว้นฟิลด์ให้ใส่คำอธิบายประกอบด้วย@Transient
ดังนั้นจะไม่ถูกแมปโดยไฮเบอร์เนต
แต่จากนั้นแจ็คสันจะไม่ทำให้เป็นอันดับเขตข้อมูลเมื่อแปลงเป็น JSON
หากคุณต้องการผสม JPA กับ JSON (ละเว้นโดย JPA แต่ยังรวมอยู่ในแจ็คสัน) ใช้@JsonInclude
:
@JsonInclude()
@Transient
private String token;
เคล็ดลับ:
คุณยังสามารถใช้JsonInclude.Include.NON_NULLและซ่อนฟิลด์ใน JSON ระหว่างการดีซีเรียลไลซ์ชันเมื่อtoken == null
:
@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;
@JsonInclude
ไม่จำเป็นต้องใช้สแต็ก: @Transient
เขตข้อมูลยังคงรวมอยู่ใน JSON (คุณยังได้รับคะแนนของฉัน: เทคนิคเองอาจมีประโยชน์มากในสถานการณ์อื่น ๆ )
หากต้องการละเว้นฟิลด์ให้ใส่คำอธิบายประกอบด้วย@Transient
ดังนั้นจะไม่ถูกแมปโดยไฮเบอร์เนต
ที่มา: Hibernate คำอธิบายประกอบ
คำตอบนี้มาช้านิดหน่อย แต่มันตอบสนองเสร็จสมบูรณ์
เพื่อหลีกเลี่ยงฟิลด์จากเอนทิตีที่จะคงอยู่ในฐานข้อมูลหนึ่งสามารถใช้หนึ่งในสองกลไก:
@Transient - คำอธิบายประกอบ JPA ที่ทำเครื่องหมายฟิลด์ว่าไม่สามารถคงอยู่ได้
คำหลักชั่วคราวใน java ระวัง - การใช้คำสำคัญนี้จะป้องกันฟิลด์ที่จะใช้กับกลไกการทำให้เป็นอนุกรมจากจาวา ดังนั้นหากจะต้องทำให้เป็นอนุกรมคุณควรใช้คำอธิบายประกอบ @Transient
มีวิธีแก้ไขหลายวิธีขึ้นอยู่กับประเภทแอตทริบิวต์
พิจารณาว่าคุณมี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
เพื่อแยกคุณสมบัติที่กำหนดออกจากการคงอยู่สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับแอตทริบิวต์นิติบุคคลคำนวณตรวจสอบบทความนี้
สมมติว่าคุณมีดังต่อไปนี้post
และpost_comment
ตาราง:
คุณต้องการแมปการlastestComment
เชื่อมโยงใน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
เพื่อละเว้นการดำเนินการเขียนในขณะที่ยังอนุญาตให้อ่านการเชื่อมโยงได้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับสมาคมคำนวณตรวจสอบบทความนี้
@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
เชื่อมโยงดูแลค่าคอลัมน์คีย์หลักของตาราง
ดังนั้นเมื่อตัวระบุเอนทิตีและการเชื่อมโยงแชร์คอลัมน์เดียวกันคุณสามารถใช้
@MapsId
เพื่อละเว้นแอททริบิวต์ตัวระบุเอนทิตีและใช้การเชื่อมโยงแทนสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการ
@MapsId
ตรวจสอบบทความนี้
insertable = false, updatable = false
อีกทางเลือกหนึ่งคือใช้insertable = false, updatable = false
สำหรับการเชื่อมโยงที่คุณต้องการละเว้นโดยไฮเบอร์เนต
ตัวอย่างเช่นเราสามารถแมปการเชื่อมโยงแบบหนึ่งต่อหนึ่งก่อนหน้านี้:
@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
คอลัมน์คีย์หลัก
post
และpost_details
ตารางเป็นตัวอย่างหรือไม่?
เพื่อให้ได้คำตอบข้างต้นฉันมีกรณีที่ใช้ไฟล์การแมป XML ที่ไม่ทำงาน@Transient
หรือtransient
... ฉันต้องใส่ข้อมูลชั่วคราวในไฟล์ xml:
<attributes>
(...)
<transient name="field" />
</attributes>
คำตอบข้างต้นไม่ได้ผลสำหรับฉันที่ใช้ Hibernate 5.2.10, Jersey 2.25.1 และ Jackson 2.8.9 ในที่สุดผมก็พบคำตอบ (การจัดเรียงของพวกเขาอ้างอิง hibernate4module แต่การทำงานเป็นเวลา 5 เกินไป) ที่นี่ ไม่มีคำอธิบายประกอบ Json ที่ใช้งาน@Transient
ได้เลย เห็นได้ชัดว่า Jackson2 นั้น 'ฉลาด' พอที่จะเพิกเฉยต่อสิ่งที่ทำเครื่องหมายด้วย@Transient
เว้นแต่ว่าคุณจะบอกอย่างชัดเจนว่าไม่ควรทำ กุญแจสำคัญคือการเพิ่มโมดูล hibernate5 (ซึ่งฉันใช้เพื่อจัดการกับหมายเหตุประกอบ Hibernate อื่น ๆ ) และปิดการใช้งานUSE_TRANSIENT_ANNOTATION
คุณสมบัติใน Jersey Application ของฉัน:
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>
@JsonProperty
@JsonInclude
@JsonSerialize + @JsonDeserialize
mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false));
นี้ก็ใช้ได้ ขอบคุณ!
บางครั้งคุณต้องการ:
ใช้ @Column(name = "columnName", insertable = false, updatable = false)
สถานการณ์ที่ดีคือเมื่อคอลัมน์ใดคอลัมน์หนึ่งคำนวณโดยอัตโนมัติโดยใช้ค่าคอลัมน์อื่น