Основные картографические концепции
При изучении Hibernate многим нравится переходить к родительско-дочерним ассоциациям, не осваивая основы сопоставления объектных отношений. Очень важно понять основные правила отображения для отдельных сущностей перед началом моделирования связей сущностей.
Спящие типы
Тип Hibernate — это мост между типом SQL и примитивом Java / типом Object.
Это типы, которые Hibernate поддерживает по умолчанию:
| Тип гибернации (org.hibernate.type) | Тип JDBC | Тип Java |
|---|---|---|
| StringType | VARCHAR | строка |
| MaterializedClob | CLOB | строка |
| TextType | LONGVARCHAR | строка |
| CharacterType | CHAR | символ или персонаж |
| BooleanType | НЕМНОГО | логическое или логическое |
| NumericBooleanType | INTEGER (например, 0 = ложь и 1 = истина) | логическое или логическое |
| YesNoType | CHAR (например, «N» или «n» = false и «Y» или «y» = true) | логическое или логическое |
| TrueFalseType | CHAR (например, «F» или «f» = false и «T» или «t» = true) | логическое или логическое |
| ByteType | TINYINT | байт или байт |
| ShortType | SMALLINT | короткий или короткий |
| IntegerType | INTEGER | int или Integer |
| LongType | BIGINT | длинный или длинный |
| FloatType | FLOAT | плавать или плавать |
| DoubleType | DOUBLE | двойной или двойной |
| BigIntegerType | NUMERIC | BigInteger |
| BigDecimalType | NUMERIC | BigDecimal |
| TimestampType | TIMESTAMP | java.sql.Timestamp или java.util.Date |
| TimeType | ВРЕМЯ | java.sql.Time |
| DateType | ДАТА | java.sql.Date |
| CalendarType | TIMESTAMP | java.util.Calendar или java.util.GregorianCalendar |
| CalendarType | ДАТА | java.util.Calendar или java.util.GregorianCalendar |
| Тип валюты | VARCHAR | java.util.Currency |
| LocaleType | VARCHAR | java.util.Locale |
| TimeZoneType | VARCHAR | java.util.TimeZone |
| UrlType | VARCHAR | java.net.URL |
| ClassType | VARCHAR | java.lang.Class |
| BlobType | большой двоичный объект | java.sql.Blob |
| ClobType | CLOB | java.sql.Clob |
| BinaryType | VARBINARY | байт [] или байт [] |
| BinaryType | большой двоичный объект | байт [] или байт [] |
| BinaryType | LONGVARBINARY | байт [] или байт [] |
| BinaryType | LONGVARBINARY | байт [] или байт [] |
| CharArrayType | VARCHAR | символ [] или символ [] |
| UUIDBinaryType | BINARY | java.util.UUID |
| UUIDBinaryType | CHAR или VARCHAR | java.util.UUID |
| UUIDBinaryType | PostgreSQL UUID | java.util.UUID |
| SerializableType | VARBINARY | Сериализуемый |
Вы всегда можете определить свои собственные пользовательские типы, как мы увидим в следующей статье.
Типы встраиваемых (он же компонент)
Вы можете сгруппировать несколько столбцов для определенного типа Java, который можно повторно использовать в модели вашего домена. Если сопоставленный Java-объект всегда зависит от некоторого внешнего объекта, вы можете выбрать тип Embeddable для такого сопоставления модели домена.
Встраиваемый объект может содержать как базовые типы, так и сопоставления ассоциаций, но он никогда не может содержать @Id. Объект Embeddable сохраняется / удаляется вместе со своим владельцем.
Предполагая, что у нас есть следующая таблица SQL:
|
1
2
3
4
5
6
7
8
|
CREATE TABLE entity_event ( id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1), entity_class VARCHAR(255), entity_id BIGINT, message VARCHAR(255), PRIMARY KEY (id) ); |
Мы могли бы сгруппировать entity_class и entity_id в объект Embeddable, который мы будем использовать в двух разных сущностях-владельцах.
Объект Embeddable выглядит так:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@Embeddablepublic class EntityIdentifier implements Serializable { @Column(name = "entity_id", nullable = true) private Long entityId; @Column(name = "entity_class", nullable = true) private Class entityClass; public EntityIdentifier() { } public EntityIdentifier(Class entityClass, Long entityId) { this.entityClass = entityClass; this.entityId = entityId; } public Class getEntityClass() { return entityClass; } public void setEntityClass(Class entityClass) { this.entityClass = entityClass; } public Long getEntityId() { return entityId; } public void setEntityId(Long entityId) { this.entityId = entityId; }} |
Связанная таблица сущностей будет наследовать связанные свойства столбцов Embeddable.
сущность
Entity — это Java-эквивалент строки таблицы SQL. Сущность должна содержать свойство @Id, сопоставляющее связанный первичный ключ таблицы.
Логика приложения вносит изменения в свойства сущностей и уведомляет об изменениях состояния постоянства контекста сущностей (сохраняются, объединяются, удаляются). Поэтому постоянный контекст будет переводить все изменения сущностей в операторы SQL.
Предполагая, что у нас есть следующие таблицы SQL:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
CREATE TABLE entity_attribute ( id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1), entity_class VARCHAR(255), entity_id BIGINT, name VARCHAR(255), VALUE VARCHAR(255), PRIMARY KEY (id) ); CREATE TABLE entity_event ( id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1), entity_class VARCHAR(255), entity_id BIGINT, message VARCHAR(255), PRIMARY KEY (id) ); |
Мы можем использовать тип EntityIdentifier Embeddable, поскольку обе таблицы содержат столбцы entity_class и entity_id.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
@Entity@Table(name = "entity_attribute")public class EntityAttribute { @Id @GeneratedValue private Long id; private String name; private String value; private EntityIdentifier entityIdentifier; public Long getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public EntityIdentifier getEntityIdentifier() { return entityIdentifier; } public void setEntityIdentifier(EntityIdentifier entityIdentifier) { this.entityIdentifier = entityIdentifier; }}@Entity@Table(name = "entity_event")public class EntityEvent { @Id @GeneratedValue private Long id; private String message; private EntityIdentifier entityIdentifier; public Long getId() { return id; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public EntityIdentifier getEntityIdentifier() { return entityIdentifier; } public void setEntityIdentifier(EntityIdentifier entityIdentifier) { this.entityIdentifier = entityIdentifier; }} |
Время тестирования
Мы создадим один EntityEvent и один EntityAttribute для данного Продукта, чтобы увидеть, как встраиваемый объект сохраняется вместе с владельцами объектов:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Testpublic void testEntityIdentifier() { doInTransaction(new TransactionCallable<Void>() { @Override public Void execute(Session session) { Product product = new Product("LCD"); session.persist(product); EntityEvent productEvent = new EntityEvent(); productEvent.setMessage(String.format("Product %s added", product.getName())); productEvent.setEntityIdentifier(new EntityIdentifier( product.getClass(), product.getId() )); session.persist(productEvent); EntityAttribute productAttribute = new EntityAttribute(); productAttribute.setName("AD_CAMPAIGN"); productAttribute.setValue("LCD_Sales"); productAttribute.setEntityIdentifier(new EntityIdentifier( product.getClass(), product.getId() )); session.persist(productAttribute); assertSame(1, session.createQuery("select ea from EntityAttribute ea where ea.entityIdentifier = :entityIdentifier") .setParameter("entityIdentifier", new EntityIdentifier(product.getClass(), product.getId())) .list().size()); return null; } });} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
Query:{[INSERT INTO product (id, name)VALUES (DEFAULT, ?) ][LCD]} Query:{[INSERT INTO entity_event (id, entity_class, entity_id, message)VALUES (DEFAULT, ?, ?, ?) ][com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier.Product,1,Product LCD added]} Query:{[INSERT INTO entity_attribute (id, entity_class, entity_id, name, VALUE)VALUES (DEFAULT, ?, ?, ?, ?) ][com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier.Product,1,AD_CAMPAIGN,LCD_Sales]} Query:{[SELECT entityattr0_.id AS id1_0_, entityattr0_.entity_class AS entity_c2_0_, entityattr0_.entity_id AS entity_i3_0_, entityattr0_.name AS name4_0_, entityattr0_.VALUE AS value5_0_FROM entity_attribute entityattr0_WHERE entityattr0_.entity_class = ? AND entityattr0_.entity_id = ? ][com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier.Product,1]} |
Вывод
Есть еще много понятий, которые мы должны охватить, прежде чем понять ассоциации сущностей. Прежде чем переходить к более сложным темам, вы всегда должны уделять время пониманию основных понятий. Мой следующий пост будет посвящен идентификаторам сущностей и всем доступным методам генерации.
- Код доступен на GitHub .
| Ссылка: | Руководство для начинающих по Hibernate Types от нашего партнера JCG Влада Михалча в блоге Влада Михалча . |