Відповіді:
@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
щоб воно не було відображене в сплячому режимі.
Джерело: Анотації зі сплячки .
Ця відповідь приходить трохи пізно, але вона завершує відповідь.
Для того, щоб уникнути поля сутності, що має зберігатися в БД, можна використовувати один з двох механізмів:
@Transient - анотація JPA, що позначає поле як нестабільне
перехідне ключове слово в java. Остерігайтеся - використання цього ключового слова запобігає використанню поля з будь-яким механізмом серіалізації від 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
таблицях як приклад?
Жоден із зазначених вище відповідей не працював для мене за допомогою Hibernate 5.2.10, Jersey 2.25.1 та Jackson 2.8.9. Я нарешті знайшов відповідь (начебто, вони посилаються на hibernate4module, але він працює і для 5) тут . Жодна з приміток Json взагалі не працювала @Transient
. Мабуть, Джексон2 досить 'розумний', щоб люб’язно ігнорувати позначені речі, @Transient
якщо ви прямо не скажете цього. Ключовим моментом було додати модуль hibernate5 (який я використовував для вирішення інших анотацій зі сплячки) та відключити USE_TRANSIENT_ANNOTATION
функцію в моєму додатку Джерсі:
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));
це рішення нарешті спрацювало. Дякую!