В моей последней статье я показал два разных способа чтения / записи постоянного состояния сущности — поле и свойство. Когда используется режим доступа к полю, JPA непосредственно считывает значения состояния из полей объекта, используя отражение. Он напрямую переводит имена полей в имена столбцов базы данных, если мы не указываем имена столбцов явно. В случае режима доступа к свойству методы getter / setter используются для чтения / записи значений состояния. В этом случае мы аннотируем методы получения состояний сущностей вместо полей, используя те же аннотации. Если мы не указываем явно имена столбцов базы данных, то они определяются в соответствии с соглашением JavaBean, то есть путем удаления части «get» из имени метода-получателя и преобразования первой буквы оставшейся части имени метода в символ нижнего регистра.
Мы можем указать, какой режим доступа использовать для сущности, используя аннотацию @Access в объявлении класса сущности. Эта аннотация принимает аргумент типа AccessType (определенный в пакете javax.persistence ), который имеет два разных значения, соответствующих двум разным режимам доступа — FIELD и PROPERTY . Например, мы можем указать режим доступа к свойству для объекта Address следующим образом:
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
@Entity @Table (name = "tbl_address" ) @Access (AccessType.PROPERTY) public class Address { private Integer id; private String street; private String city; private String province; private String country; private String postcode; private String transientColumn; @Id @GeneratedValue @Column (name = "address_id" ) public Integer getId() { return id; } public Address setId(Integer id) { this .id = id; return this ; } public String getStreet() { return street; } public Address setStreet(String street) { this .street = street; return this ; } public String getCity() { return city; } public Address setCity(String city) { this .city = city; return this ; } public String getProvince() { return province; } public Address setProvince(String province) { this .province = province; return this ; } public String getCountry() { return country; } public Address setCountry(String country) { this .country = country; return this ; } public String getPostcode() { return postcode; } public Address setPostcode(String postcode) { this .postcode = postcode; return this ; } } |
Несколько замечаний по поводу приведенного выше примера:
- Как обсуждалось ранее, теперь мы аннотируем метод получения идентификатора сущности с помощью аннотаций @Id , @GeneratedValue и @Column .
- Поскольку теперь имена столбцов будут определяться путем анализа методов получения, нам больше не нужно помечать поле transientColumn аннотацией @Transient . Однако если у объекта Address есть какой-либо другой метод, имя которого начинается с «get», то нам нужно применить к нему @Transient .
Если у объекта нет явной информации о режиме доступа, как и у нашего объекта Address, который мы создали в первой части этой серии , то JPA принимает режим доступа по умолчанию. Это предположение сделано не случайно. Вместо этого JPA сначала пытается выяснить расположение аннотации @Id . Если для поля используется аннотация @Id , то предполагается режим доступа к полю. Если аннотация @Id используется в методе получения, тогда предполагается режим доступа к свойству. Таким образом, даже если мы удалим аннотацию @Access из объекта Address в приведенном выше примере, сопоставление все равно будет действительным, и JPA перейдет в режим доступа к свойству:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Entity @Table (name = "tbl_address" ) public class Address { private Integer id; private String street; private String city; private String province; private String country; private String postcode; private String transientColumn; @Id @GeneratedValue @Column (name = "address_id" ) public Integer getId() { return id; } // Rest of the class........ |
Несколько важных моментов, которые следует помнить о режимах доступа:
- Никогда не следует объявлять поле общедоступным, если вы используете режим доступа к полю. Все поля сущности должны иметь либо закрытый (лучший!), Защищенный тип доступа, либо тип доступа по умолчанию. Причина этого заключается в том, что объявление полей как открытых позволит любому незащищенному классу иметь прямой доступ к состояниям объекта, что может легко победить реализацию провайдера. Например, предположим, что у вас есть объект, все поля которого общедоступны. Теперь, если этот объект является управляемым объектом (что означает, что он был сохранен в базе данных), и любой другой класс изменяет значение его идентификатора , а затем вы пытаетесь сохранить изменения обратно в базу данных, вы можете столкнуться с непредсказуемым поведением (I постараюсь подробно остановиться на этой теме в следующей статье). Даже сам класс сущности должен манипулировать полями только во время инициализации (т. Е. Внутри конструкторов).
- В случае режима доступа к свойству, если мы применим аннотации к методам-установщикам, а не к методам-получателям, они просто будут игнорироваться.
Также возможно смешать оба этих типа доступа. Предположим, что вы хотите использовать режим доступа к полю для всех состояний объекта, кроме одного, а для этого одного оставшегося состояния вы хотели бы использовать режим доступа к свойству, потому что вы хотите выполнить некоторое преобразование перед записью / после чтения значения состояния в и из база данных. Вы можете сделать это легко, выполнив следующие действия:
- Пометьте объект аннотацией @Access и укажите AccessType.FIELD в качестве режима доступа для всех полей.
- Отметьте поле, для которого вы не хотите использовать режим доступа к полю, с помощью аннотации @Transient .
- Пометьте метод получения свойства аннотацией @Access и укажите AccessType.PROPERTY в качестве режима доступа.
В следующем примере демонстрируется этот подход, поскольку почтовый индекс был изменен для использования режима доступа к свойству:
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
@Entity @Table (name = "tbl_address" ) @Access (AccessType.FIELD) public class Address { @Id @GeneratedValue @Column (name = "address_id" ) private Integer id; private String street; private String city; private String province; private String country; /** * postcode is now marked as Transient */ @Transient private String postcode; @Transient private String transientColumn; public Integer getId() { return id; } public Address setId(Integer id) { this .id = id; return this ; } public String getStreet() { return street; } public Address setStreet(String street) { this .street = street; return this ; } public String getCity() { return city; } public Address setCity(String city) { this .city = city; return this ; } public String getProvince() { return province; } public Address setProvince(String province) { this .province = province; return this ; } public String getCountry() { return country; } public Address setCountry(String country) { this .country = country; return this ; } /** * We are now using property access mode for reading/writing * postcode */ @Access (AccessType.PROPERTY) public String getPostcode() { return postcode; } public Address setPostcode(String postcode) { this .postcode = postcode; return this ; } } |
Здесь важно отметить, что если мы не аннотируем класс аннотацией @Access для явного указания режима доступа к полям в качестве режима по умолчанию, и мы аннотируем как поля, так и методы получателя, то результирующее поведение отображения будет неопределенным. Это означает, что результат будет полностью зависеть от поставщика сохраняемости, то есть один поставщик может выбрать режим доступа к полю по умолчанию, другой может использовать режим доступа к свойству или может принять решение об исключении!
Вот и все на сегодня. Если вы обнаружите какие-либо проблемы / у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь комментировать!
До скорого.
Ссылка: | JPA Tutorial: Mapping Entities — часть 3 от нашего партнера JCG Саима Ахмеда в блоге Codesod . |