Автор оригинала: Vlad Mihalcea.
Вступление
Как я объяснил в этой предыдущей статье , вы можете сопоставить вычисляемые свойства с помощью Hibernate @Formula
, и значение генерируется во время запроса.
В этом посте вы увидите, как можно рассчитать свойство сущности во время ВСТАВКИ или ОБНОВЛЕНИЯ.
Модель предметной области
Предполагая, что у нас есть следующее Герой
сопоставление сущностей:
@Entity(name = "Hero") public class Hero { @Id private Long id; private String firstName; private String lastName; private String middleName1; private String middleName2; private String middleName3; private String middleName4; private String middleName5; @Generated( value = GenerationTime.ALWAYS ) @Column(columnDefinition = "AS CONCAT(" + " COALESCE(firstName, ''), " + " COALESCE(' ' + middleName1, ''), " + " COALESCE(' ' + middleName2, ''), " + " COALESCE(' ' + middleName3, ''), " + " COALESCE(' ' + middleName4, ''), " + " COALESCE(' ' + middleName5, ''), " + " COALESCE(' ' + lastName, '') " + ")") private String fullName; //Getters and setters omitted for brevity public String getFullName() { return fullName; } }
Свойство Полное имя
вычисляется с помощью функции SQL Server CONCAT
, включая все имена. Функция COALESCE
используется, потому что CONCAT
не использует разделитель в SQL Server.
Определение столбца
полезно только при создании схемы базы данных из аннотаций JPA (что не следует делать в рабочей среде). Поскольку мы предоставили пользовательское @Определение столбца
, базовая таблица базы данных выглядит следующим образом:
CREATE TABLE Hero ( id BIGINT NOT NULL , firstName VARCHAR(255) , fullName AS CONCAT(COALESCE(firstName, ''), COALESCE(' ' + middleName1, ''), COALESCE(' ' + middleName2, ''), COALESCE(' ' + middleName3, ''), COALESCE(' ' + middleName4, ''), COALESCE(' ' + middleName5, ''), COALESCE(' ' + lastName, '')) , lastName VARCHAR(255) , middleName1 VARCHAR(255) , middleName2 VARCHAR(255) , middleName3 VARCHAR(255) , middleName4 VARCHAR(255) , middleName5 VARCHAR(255) , PRIMARY KEY ( id ) )
@Сгенерированная
аннотация используется для указания режима гибернации при вычислении соответствующего значения столбца, и она может принимать два значения:
ВСТАВИТЬ
– означает, что значение столбца вычисляется во время вставкиВСЕГДА
– означает, что значение столбца вычисляется как во время вставки, так и во время обновления
Время тестирования
Теперь, при сохранении Герой
сущность:
doInJPA( entityManager -> { Hero heroine = new Hero(); heroine.setId( 1L ); heroine.setFirstName( "Agustina" ); heroine.setMiddleName1( "Raimunda" ); heroine.setMiddleName2( "María" ); heroine.setMiddleName3( "Saragossa" ); heroine.setLastName( "Domènech" ); entityManager.persist( heroine ); LOGGER.info("After entity persist action"); entityManager.flush(); assertEquals( "Agustina Raimunda María Saragossa Domènech", heroine.getFullName() ); } );
Hibernate создает следующие инструкции SQL:
-- After entity persist action INSERT INTO Hero (firstName, lastName, middleName1, middleName2, middleName3, middleName4, middleName5, id) VALUES ('Agustina', 'Domènech', 'Raimunda', 'María', 'Saragossa', NULL(VARCHAR), NULL(VARCHAR), 1) SELECT h.fullName as fullName3_0_ FROM Hero h WHERE h.id = 1
Обратите внимание на запрос SELECT
, который выдается после операции flush
, которая позволяет Hibernate извлекать вычисляемое свойство сущности.
При обновлении и загрузке объекта:
doInJPA( entityManager -> { Hero heroine = entityManager.find( Hero.class, 1L ); heroine.setMiddleName1( null ); heroine.setMiddleName2( null ); heroine.setMiddleName3( null ); heroine.setLastName( "de Aragón" ); LOGGER.info("After entity update action"); entityManager.flush(); assertEquals("Agustina de Aragón", heroine.getFullName()); } );
Hibernate создает следующие инструкции SQL:
SELECT h.id AS id1_0_0_, h.firstName AS firstNam2_0_0_, h.fullName AS fullName3_0_0_, h.lastName AS lastName4_0_0_, h.middleName1 AS middleNa5_0_0_, h.middleName2 AS middleNa6_0_0_, h.middleName3 AS middleNa7_0_0_, h.middleName4 AS middleNa8_0_0_, h.middleName5 AS middleNa9_0_0_ FROM Hero h WHERE h.id = 1 UPDATE Hero SET firstName = 'Agustina', lastName = 'de Aragón', middleName1 = NULL(VARCHAR), middleName2 = NULL(VARCHAR), middleName3 = NULL(VARCHAR), middleName4 = NULL(VARCHAR), middleName5 = NULL(VARCHAR) WHERE id = 1 -- After entity update action SELECT h.fullName as fullName3_0_ FROM Hero h WHERE h.id = 1
Опять же, последний запрос SELECT
используется для обеспечения синхронизации управляемой сущности с базовой строкой таблицы.
Вывод
Сопоставление вычисляемых свойств объектов с помощью Hibernate довольно просто, и у вас есть несколько способов достижения этой цели.
Аннотация @Generated
позволяет динамически создавать свойства объектов при вставке или обновлении на основе других значений свойств.