Судя по всей прочитанной мною документации, следующий код не должен работать; записи Java неизменяемы и не будут работать с JPA. Однако следующий код работает. Я могу успешно получить данные из базы данных. Может ли JPA поддерживать записи Java в сценариях только для чтения?
@Embeddable
public record TaxableLimitAmountId(@Column(name = "TAX_YR") String taxYr,
@Column(name = "TAXL_LMT_UID") int taxableLimitUniqueId,
@Column(name = "EFF_STDT", columnDefinition = "DATE") Date effectiveStartDate)
implements Serializable {
private static final long serialVersionUID = 1L;
}
@Entity
@Table(name = "TableName", schema = "schema")
public record TaxableLimitAmountEntity(
@EmbeddedId TaxableLimitAmountId taxableLimitAmountId,
@Column(name = "TAXL_LMT_AMT", columnDefinition = "DECIMAL") BigDecimal taxableLimitAmount,
@Column(name = "EFF_ENDT", columnDefinition = "DATE") Date effectiveEndDate,
@Column(name = "INSRT_TS") Timestamp insertTimeStamp,
@Column(name = "LU_TS") Timestamp updateTimeStamp) {
}
public record FicaMaxData(int taxYr, BigDecimal taxableLimitAmount) {
}
@Repository
public interface TaxableLimitAmountRepo
extends JpaRepository<TaxableLimitAmountEntity, Integer> {
@Query("SELECT NEW gov.ssa.irsrptg.repo.FicaMaxData(CAST(tla.taxableLimitAmountId.taxYr as INTEGER),tla.taxableLimitAmount) FROM TaxableLimitAmountEntity tla "
+ "WHERE tla.taxableLimitAmountId.taxableLimitUniqueId = 1")
List<FicaMaxData> getFicaMaxAllYears();
@Query("SELECT tla.taxableLimitAmount FROM TaxableLimitAmountEntity tla "
+ "WHERE tla.taxableLimitAmountId.taxableLimitUniqueId = 1 and tla.taxableLimitAmountId.taxYr = :taxYr")
BigDecimal getFicaMaxSpecificYear(@Param("taxYr") String taxYr);
}
Hibernate выдает следующее предупреждение, но не выдает никаких ошибок
o.h.m.i.EntityInstantiatorPojoStandard : HHH000182: No default (no-argument) constructor for class: gov.ssa.irsrptg.repo.TaxableLimitAmountEntity (class must be instantiated by Interceptor)
Я использую Java 17, Spring Boot 3.2.6, Spring Data Jpa 3.2.6 и Hibernate 6.4.8.Final.
getFicaMaxAllYears()
даже не создает экземпляры TaxableLimitAmountEntity
, а только использует метаинформацию для создания SQL-запроса и сопоставления с конструктором FicaMaxData
. Кроме того, Hibernate должен иметь возможность создавать экземпляр записи посредством отражения (как сказал Гимби, записи представляют собой более синтаксический сахар, хотя отражение также накладывает некоторые ограничения на записи) и, таким образом, иметь возможность загружать эти экземпляры - возможно, они даже будут отсоединены по мере изменений. от них этого не ожидалось.
Выбор @Gimby без нового приводит к поломке кода.
JPA не требует создания исключений для записей: все, что не указано, просто не поддерживается — используйте на свой страх и риск. То, что его можно прочитать из базы данных и созданных экземпляров, связано с деталями реализации конкретных поставщиков JPA, но не будет единообразным. Запись или изменения в БД могут привести к сбою, поскольку JPA требует сохранения идентичности объекта, что означает обновление значений для кэшированных объектов при наличии изменений.
Утверждение «JPA не работает с записями для сущностей» представляет собой короткую форму: «Есть вещи, которые JPA требует от сущности, что невозможно с записями».
Жестким ограничением здесь является неизменяемость, которая не позволяет JPA работать должным образом, отслеживая изменения в объекте.
Конечно, это не означает, что реализация JPA должна немедленно взорваться вам в лицо, если она обнаружит запись. Некоторые вещи могут работать нормально, потому что эти функции не нужны для данного варианта использования. Например, вам не нужен конструктор по умолчанию, когда вы используете выражение конструктора. Или ваша реализация JPA может обойти некоторые ограничения JPA, как это делает Hibernate из-за отсутствия конструктора по умолчанию, на что намекает
Нет конструктора по умолчанию (без аргументов) для класса: gov.ssa.irsrptg.repo.TaxableLimitAmountEntity (экземпляр класса должен быть создан Interceptor)
Так что да: некоторые вещи могут сработать.
До сих пор я не видел официального заявления JPA или Hibernate о том, какие именно вещи работают, и я бы не хотел полагаться на функции, которые просто работают, поскольку они могут перестать работать в следующем выпуске.
Однако это своего рода обман: вы делаете
select new
, который не является «обычным» JPA, это «обход проблем с соглашениями» JPA. Интересно, сработает ли это, если делать регулярноselect bla from TaxableLimitAmountEntity bla
. Возможно, записи — это, по сути, синтаксический сахар. Но без официальной поддержки я бы не рискнул.