-
Architect Solution - RiscoSoftware
-
VavaTech trener : Spring ekosystem, JPA , EIP Camel
-
Sages trener : JPA , EIP - Apache Camel
-
twitter przodownikR1
image:https://pbs.twimg.com/profile_images/425289501980639233/tUWf7KiC.jpeg [role='img-circle']
-
Hibernate in Action
-
Java Persistence with Hibernate
-
Java JEE 6
-
Pro JPA 2
-
Pro JPA 2: Mastering the Java™ Persistence API (Expert’s Voice in Java Technology)
-
Hibernate from Novice to Professional
-
Spring Data Modern Data Access for Enterprise Java
-
Spring Data
-
Spring Boot
-
Spring Essentials
-
Spring in Action
-
etc
-
oznacza klasy klasy, które mają brać udział w procesie utrwalania
-
taka klasa może być abstract
-
klasa nie może być final
-
klasa nie może zawierać pola i metody final
-
klasa musi posiadać bezargumentowy konstruktor
-
klasa musi posiadać klucz główny @Id
Caution
|
Dla komunikacji (distributed/web/session/serializable) powinna implementować Serializable. Klasa posiada wyróżnioną tożsamość |
-
Przykład
@Entity
public class Simple {
...
}
-
@NaturalId
-
Rekomendowany zamiast klucza techniczego
-
Unikalny w ramach tabeli
-
JPA
-
@Table(uniqueConstraints = @UniqueConstraint(columnNames={column_1, …, column_n})) , nullable = false
-
@EmbeddedId, @IdClass
-
-
public class Book {
@Id
@GeneratedValue
private Long id;
private String name;
....
@NaturalId
private String isbn;
...
}
-
każda klasa encyjna musi posiadać unikalny identyfikator.
-
Przykład
-
@Id
public Long id;
-
Database sequence - wykorzystuje sekwencje. Wsparcie dla baz DB2, PostgreSQL, Oracle, SAP DB.
-
Eliminacja 'roundtrip database' : hi/lo, pooled etc
-
-
Native generator - wybiera jedną ze strategii generowania identyfikatorów : identity, sequence, hilo w zależności od możliwości bazy
-
wsparcie dla kolumn identity w bazach DB2, MySQL, MS SQL Server, Sybase, HypersonicSQL.
-
-
Increment generator (Identity)
-
Identity uniemożliwia jdbc batch insert
-
-
Hilo generator - identyfikatory są unikalne w ramach całej bazy.
-
UUID - generuje Stringi (unikalny w sieci adres ip + znacznik czasu). Jest to kosztowne rozwiązanie.
-
Baza danych : UUID type → Binary(16) → char(32)
-
Oracle RAW(16)
-
-
assigned - pozwala aplikacji nadać identyfikator zanim obiekt zostanie zapisany.(persist, save)
-
używa blokad na wierszach
-
używa osobnej transakcji na połączenie
-
klucze główne trzymane są w specjalnej tabeli
-
Przykład
-
@TableGenerator(name="Book_Gen", table="ID_GEN",pkColumnName="GEN_NAME", valueColumnName="GEN_VAL", initialValue=10000, allocationSize=100)
@Id
@GeneratedValue(strategy = GenerationType.TABLE,generator="Book_Gen")
private Long id;
@Entity public class Employee {
...
@TableGenerator(
name="empGen",
table="ID_GEN",
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="EMP_ID",
allocationSize=1)
@Id
@GeneratedValue(strategy=TABLE, generator="empGen")
int id;
...
}
-
Przykład
public class BookPK implements Serializable{
private String name;
private String isbn;
public int hashCode() {
return ...;
}
public boolean equals(Object obj) {
return ...;
}
}
@IdClass(BookPK.class)
@Entity
public class Book{
@Id
private String id;
@Id
private String isbn;
}
-
Przykład
@Entity
class User {
@EmbeddedId
@AttributeOverride(name="firstName", column=@Column(name="fld_firstname")
UserId id;
Integer age;
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
}
NOTE : Może być wykorzystywany przez @ElementCollection
-
Przykład
@Entity
public class Employee {
@Id
@Column(name="EMP_ID")
private long id;
...
@ElementCollection
@CollectionTable(
name="PHONE",
joinColumns=@JoinColumn(name="OWNER_ID")
)
private List<Phone> phones;
...
}
@Embeddable
public class Phone {
private String type;
private String areaCode;
@Column(name="P_NUMBER")
private String number;
...
}
-
Przykład
@Entity
public class Employee {
@Id
private long id;
...
@Embedded
@AttributeOverrides({
@AttributeOverride(name="startDate", column=@Column(name="START_DATE")),
@AttributeOverride(name="endDate", column=@Column(name="END_DATE"))
})
private Period employmentPeriod;
...
}
@Entity
public class User {
@Id
private long id;
...
@Embedded
@AttributeOverrides({
@AttributeOverride(name="startDate", column=@Column(name="SDATE")),
@AttributeOverride(name="endDate", column=@Column(name="EDATE"))
})
private Period period;
...
}
-
domyślnie nazwa tabeli jest taka sama jak nazwa klasy.
-
jeśli domyślne ustawienie jest nie wystarczające z różnych powodów możemy użyć @Table
-
Przykład
-
@Table(name = "ITEMS",uniqueConstraints =@UniqueConstraint(name = "UNQ_NAME",columnNames = { "ITEM_NAME" })
)
public class Item extends AbstractEntity {
private static final long serialVersionUID = 5474170031394030929L;
@Column(name="ITEM_NAME")
private String name;
}
create table ITEMS (
id bigint not null,
ITEM_NAME varchar(255),
primary key (id)
)
alter table ITEMS add constraint UNQ_NAME unique (ITEM_NAME)
<entity-mappings>
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema name="purchasing"/>
</persistence-unit-defaults>
</persistence-unit-metadata>
....
</entity-mappings>
-
Przykład
@Table(name = "ITEMS",
indexes = {@Index(name = "IDX_USERNAME", columnList = "ITEM_NAME")}
public class Item extends AbstractEntity {
@Column(name="ITEM_NAME")
private String name;
}
create table ITEMS (
id bigint not null,
ITEM_NAME varchar(255),
primary key (id)
)
create index IDX_USERNAME on ITEMS (ITEM_NAME)
Warning
|
Index Shotgun |
-
Stosowanie indeksu bez żadnego planu
-
całkowity brak lub zbyt mało indeksów
-
zbyt dużo indeksów, które niczego nie wnoszą
-
wykonywanie zapytań, które nie bazują na indeksach
-
nadmiarowe indeksy złożone
-
indeksy pokrywające - wynik zapytania pochodzi tylko z indeksu , bez odczytywania wierszy z tabeli
-
Warning
|
indeksowanie długich łańuchów typów |
NOTE : Zasada MENTOR
-
MEASURE (mierzenie) - wykrycie, które zapytania zajmują najwięcej czasu, monitoriwanie i wykrywanie wąskich gardeł
-
TKProf
-
SQL Trace
-
Dziennik zdarzeń
-
pgFouine
-
Note
|
Wszechobecny monitoring |
-
Explain (wyjaśnianie) - plan wykonania QEP
-
Polecenie Explain
-
-
Nominate (Wskazywanie) - gdzie zapytanie dostaje dane bez użycia indeksu
-
MySql Enterprise Query Analyzer
-
Oracle Automatic SQL Tuning Advisor
-
-
Test (Testowanie) - po optymalizacji powtarzamy pierwsze kroki (Measure, Explain, ewentualnie Nominate )
-
Optimize (Optymalizacja)
-
pamięć podręczna vs I/O
-
Mysql : LOAD INDEX INTO CACHE
-
-
Rebuild (Przebudowa)
-
zrównoważenie. optymalny/niezrównoważony (jak defragmentacja systemu plików)
-
konserwacja indeksów
-
Mysql : Analyze Table , Optimize Table
-
Oracle : Alter Index …. Rebuild
-
PostgreSQl : Vacuum , Analyze
-
-
analogiczne zachowanie do adnotacji @Table
-
insertable/updatable - określa czy dana kolumna będzie brała udział w operacjach insert/update
-
zapewnienie o read-only
-
zapewnia, że dostawca nie będzie brał udziału w aktualizacja lub dodaniu danych
-
@Column, @JoinColumn(name="BookStoreId", insertable=false, updatable=false)
-
-
unique - określa czy dana kolumna ma być traktowana jako klucz unikalny
-
nullable - czy kolumna może lub nie pozwalać na wartości null
-
length - długość kolumny dla String’a
-
precision - precyzja dla wartości BigDecimal
-
Przykład
-
@Column(name = "retryattempt", columnDefinition = "numeric", nullable = true)
private int retryAttempt = 0;
@Column(name = "messageerror", columnDefinition = "nvarchar")
private String messageError;
@Column(name = "messagebody", length = Integer.MAX_VALUE, columnDefinition = "nvarchar")
private String body;
@Column(name = "detailstatus", columnDefinition = "nvarchar")
@Enumerated(EnumType.STRING)
private DetailStatus status;
-
Przykład 1
@Column(nullable=false,scale=2,precision=2)
private BigDecimal price;
price decimal(2,2) not null
-
Przykład 2
@Column
private BigDecimal price;
price decimal(19,2)
-
Przykład 3
@Column(name="ITEM_NAME",length=20,unique=true)
create table Item (
id bigint not null,
version bigint,
ITEM_NAME varchar(20),
price decimal(2,2) not null,
primary key (id)
)
alter table Item add constraint UK_bjye5lp3xnccmg4ovtumigp3v unique (ITEM_NAME)
-
Przykład 4
@Column(columnDefinition ="varchar(15) not null unique check (not substring(lower(OWNER), 0, 5) = 'admin')")
private String owner;
create table Item (
id bigint not null,
version bigint,
ITEM_NAME varchar(20),
owner varchar(15) not null unique check (not substring(lower(OWNER), 0, 5) = 'admin'),
price decimal(2,2) not null,
primary key (id)
-
Przykład
@org.hibernate.annotations.Check(
constraints = "AUCTIONSTART < AUCTIONEND"
)
public class Offer extends AbstractEntity{
@NotNull
protected Date auctionStart;
@NotNull
protected Date auctionEnd;
}
create table Offer (
id bigint not null,
version bigint,
auctionEnd binary(255) not null,
auctionStart binary(255) not null,
offer_value decimal(19,2),
ITEM_ID bigint not null,
primary key (id),
check (AUCTIONSTART < AUCTIONEND)
)
-
określa czy pole ma być opcjonalne (przydatne podczas generowania schematu przez Hibernate).
-
określa również sposób pobierania danych, czy pole ma być wypełniane od razu przy odczycie obiektu czy dopiero przy pierwszym odwołaniu.
-
umożliwia osadzanie nieencyjnych obiektów Java w objektach encyjnych
-
Przykład
@Embeddable
public class EmploymentPeriod {
@Column(name="START_DATE")
private java.sql.Date startDate;
@Column(name="END_DATE")
private java.sql.Date endDate;
....
}
@Entity
public class Employee {
@Id
private long id;
...
@Embedded
private EmploymentPeriod period;
...
}
@Embeddable
public class Address {
private String line1;
private String line2;
@Embedded
private ZipCode zipCode;
...
@Embeddable
public static class Zip {
private String postalCode;
private String plus4;
...
}
}
@Entity
public class Person {
@Id
private Integer id;
@Embedded
private Name name;
...
}
@Multiple embeddable types
@Entity
public class Contact {
@Id
private Integer id;
@Embedded
private Name name;
@Embedded
private Address homeAddress;
@Embedded
private Address mailingAddress;
@Embedded
private Address workAddress;
...
}
@AttributeOverride
-
Przykład
@Entity
public class Contact {
@Id
private Integer id;
@Embedded
private Name name;
@Embedded
@AttributeOverrides(
@AttributeOverride(
name = "line1",
column = @Column( name = "home_address_line1" ),
),
@AttributeOverride(
name = "line2",
column = @Column( name = "home_address_line2" )
),
@AttributeOverride(
name = "zipCode.postalCode",
column = @Column( name = "home_address_postal_cd" )
),
@AttributeOverride(
name = "zipCode.plus4",
column = @Column( name = "home_address_postal_plus4" )
)
)
private Address homeAddress;
@Embedded
@AttributeOverrides(
@AttributeOverride(
name = "line1",
column = @Column( name = "mailing_address_line1" ),
),
@AttributeOverride(
name = "line2",
column = @Column( name = "mailing_address_line2" )
),
@AttributeOverride(
name = "zipCode.postalCode",
column = @Column( name = "mailing_address_postal_cd" )
),
@AttributeOverride(
name = "zipCode.plus4",
column = @Column( name = "mailing_address_postal_plus4" )
)
)
private Address mailingAddress;
@Embedded
@AttributeOverrides(
@AttributeOverride(
name = "line1",
column = @Column( name = "work_address_line1" ),
),
@AttributeOverride(
name = "line2",
column = @Column( name = "work_address_line2" )
),
@AttributeOverride(
name = "zipCode.postalCode",
column = @Column( name = "work_address_postal_cd" )
),
@AttributeOverride(
name = "zipCode.plus4",
column = @Column( name = "work_address_postal_plus4" )
)
)
private Address workAddress;
...
}
-
mapowanie enum
-
Przykład
-
@Entity
public class Person {
@Enumerated
public Gender gender;
public static enum Gender {
MALE,
FEMALE
}
}
-
@AttribureConverter
-
Przykład
-
public enum Gender {
MALE('M'),
FEMALE('F');
private final char code;
private Gender( char code ) {
this.code = code;
}
public static Gender fromCode( char code ) {
if ( code == 'M' || code == 'm' ) {
return MALE;
}
if ( code == 'F' || code == 'f' ) {
return FEMALE;
}
throw...
}
public char getCode() {
return code;
}
}
@Entity
public class Person {
...
@Basic
@Convert( converter = GenderConverter.class )
public Gender gender;
}
@Converter
public class GenderConverter implements AttributeConverter<Character, Gender> {
public Character convertToDatabaseColumn( Gender value ) {
if ( value == null ) {
return null;
}
return value.getCode();
}
public Gender convertToEntityAttribute( Character value ) {
if ( value == null ) {
return null;
}
return Gender.fromCode( value );
}
}
@Entity
public class Product {
...
@Lob
@Basic
public Clob description;
...
}
-
Przykład
@Entity
public class Product {
...
@Lob
@Basic
public Clob description;
...
@Lob
@Basic
public char[] description;
@Lob
@Basic
public Blob instructions;
@Lob
@Basic
public byte[] instructions;
}
Note
|
Partycjonowanie : 'Vertical Partitioning' np z użyciem @OneToOne |
Caution
|
Wydajność |
Note
|
Użyj systemu plików |
Note
|
Niezależna tabela |
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>${hibernate.version}</version>
</dependency>
-
java.time.LocalTime
-
java.time.OffsetTime
INSERT INTO DateEvent( timestamp, id ) VALUES ( '16:51:58', 1 )
-
Przykład
@Converter
public class PeriodStringConverter implements AttributeConverter<Period, String> {
@Override
public String convertToDatabaseColumn(Period attribute) {
return attribute.toString();
}
@Override
public Period convertToEntityAttribute(String dbData) {
return Period.parse(dbData);
}
}
@Entity
public class Event {
@Convert(converter = PeriodStringConverter.class)
private Period span;
}
-
Przykład
@Formula("obj_length * obj_height * obj_width")
private long objectVolume;
@Formula("UPPER(name)")
private String capitalName;
@Formula("(SELECT c.name FROM category c WHERE c.id=category_id)")
private String categoryName;
@Entity
@Table(name="EMPLOYEE")
@SecondaryTable(name="EMP_DATA",
pkJoinColumns = @PrimaryKeyJoinColumn(name="EMP_ID", referencedColumnName="ID")
)
public class Employee {
...
@Column(name="YEAR_OF_SERV", table="EMP_DATA")
private int yearsOfService;
@OneToOne
@JoinColumn(name="MGR_ID", table="EMP_DATA", referencedColumnName="ID")
private Employee manager;
...
}
-
Przykład
Employee employee = new Employee();
employee.setId(1);
employee.setName("przodownik");
session.saveOrUpdate(employee);
Hibernate: update employee set name=?, version=? where id=? and version=?
-
Przykład
@OrderColumn(name = "index_id")
private List<Change> changes = new ArrayList<>();
-
Przykład
@Entity
public class Phone {
@ManyToOne
@JoinColumn(name = "person_id",
foreignKey = @ForeignKey(name = "PERSON_ID_FK")
)
}
CREATE TABLE Phone (
id BIGINT NOT NULL ,
number VARCHAR(255) ,
person_id BIGINT ,
PRIMARY KEY ( id )
)
ALTER TABLE Phone ADD CONSTRAINT PERSON_ID_FK FOREIGN KEY (person_id) REFERENCES Person
-
Przykład
@org.hibernate.annotations.Type( type = "nstring" )
private String name;
@org.hibernate.annotations.Type( type = "materialized_nclob" )
private String description;
@UniqueConstraint(columnNames = { "id" , "empCode"}))
-
Przykład
@ElementCollection(fetch=FetchType.LAZY)
@CollectionTable(name = "email")
@IndexColumn(name="email_index")
private List<String> emails;
@ElementCollection(targetClass = CarBrands.class)
@Enumerated(EnumType.STRING)
private List<CarBrands> brands;
}
public enum CarBrands {
SUZUKI, STAR, FERRARI,JAGUAR;
}
-
kolekcja może zostać uporządkowana według określonych kryteriów
-
w przypadku kolekcji uporządkowanej wykorzystać należy typ List
-
wykonywany przez wyrażenie SQL SELECT
@Entity
public class Book {
@ElementCollection
@CollectionTable(name = "Chapters")
@Column(name = "shortDest")
@org.hibernate.annotations.OrderBy(clause = "shortDesc desc")
protected Set<String> chapters = new LinkedHashSet<String>();
}
Note
|
@SortNatural i @SortComparator |
-
Przykład
@OneToMany(mappedBy="user")
@OrderBy("lastName")
protected List<User> children;
-
name to nazwa tabeli
-
joinColumns – kolumna tabeli złączenia, stanowiąca klucz dla encji
-
inverseJoinColumns – kolumna tabel złączenia, stanowiąca klucz dla encji po drugiej stronie relacji
Strategia |
Domyślny tryb |
OneToMany |
LAZY |
ManyToOne |
EAGER |
ManyToMany |
LAZY |
OneToOne |
EAGER |
@JoinColumn + @JoinTable
-
One-To-One 1:1
@Entity
public class Message {
@Id
Long id;
@Column
String content;
@OneToOne
Email email;
}
//ommit mutators and accessors
}
-
One-To-Many 1:N Za pomoca kluczu obcego
-
Przykład
-
@Entity
public class Item extends AbstractEntity {
private String name;
private BigDecimal price;
@OneToMany(fetch = FetchType.LAZY) // Defaults to EAGER
@JoinColumn(name = "ITEM_ID")
private List<Offer> offers;
}
-
Przykład
@Entity
public class Offer extends AbstractEntity{
@Column(name="offer_value")
private BigDecimal value;
}
-
Generowany SQL :
create table Item (
id bigint not null,
version bigint,
name varchar(255),
price decimal(19,2),
primary key (id)
)
create table Offer (
id bigint not null,
version bigint,
offer_value decimal(19,2),
ITEM_ID bigint,
primary key (id)
)
alter table Offer
add constraint FKp6fm8wffictppkc0m3ufurbpy
foreign key (ITEM_ID)
references Item
Za pomoca kluczu głównego
-
Many-To-One N:1
-
Przykład
-
@Entity
public class Item extends AbstractEntity{
private String name;
private BigDecimal price;
}
@Entity
public class Offer extends AbstractEntity{
@ManyToOne(fetch = FetchType.LAZY) // Defaults to EAGER
@JoinColumn(name = "ITEM_ID", nullable = false,
foreignKey = @ForeignKey(name = "FK_ITEM_ID") )
private Item item;
@Column(name="offer_value")
private BigDecimal value;
}
create table Item (
id bigint not null,
version bigint,
name varchar(255),
price decimal(19,2),
primary key (id)
)
create table Offer (
id bigint not null,
version bigint,
offer_value decimal(19,2),
ITEM_ID bigint not null,
primary key (id)
)
alter table Offer
add constraint FK_ITEM_ID
foreign key (ITEM_ID)
references Item
-
Many-To-Many N:M
public class ProjectType {
@Id
@GeneratedValue
private long id;
@ManyToOne
private Employee employee;
@Column(name="PROJ_TYPE")
private String type;
@ManyToMany
private List<Project> projects;
}
-
@ManyToAny
Pozwala na polimorficzne asocjacje klas z różnumi tabelami
public interface Property {
public String getName();
public String asString();
}
@Entity
@Table(name = "long_property")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class LongProperty extends AbstractEntity implements Property {
private static final long serialVersionUID = -1275713912865305945L;
private String name;
private Long value;
@Override
public String asString() {
return Long.toString(value);
}
@Override
public String getName() {
return name;
}
}
@Entity
@Table(name="string_property")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class
StringProperty extends AbstractEntity implements Property {
private static final long serialVersionUID = -4928360703691383693L;
private String name;
private String value;
@Override
public String getName() {
return name;
}
@Override
public String asString() {
return value;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
@Table(name = "Property_Example")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class PropertyMap extends AbstractEntity {
private static final long serialVersionUID = 6842457337123716680L;
private String name;
@ManyToAny(metaColumn = @Column(name = "property_type"))
@AnyMetaDef(idType = "integer", metaType = "string", metaValues = { @MetaValue(value = "S", targetEntity = StringProperty.class),
@MetaValue(value = "I", targetEntity = IntegerProperty.class) })
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
@JoinTable(name = "obj_properties", joinColumns = @JoinColumn(name = "obj_id"), inverseJoinColumns = @JoinColumn(name = "property_id"))
private List<Property> properties = newArrayList();
public PropertyMap(String name) {
this.name = name;
}
}
create table Property_Example (
id bigint not null,
version bigint,
name varchar(255),
primary key (id)
);
create table obj_properties (
obj_id bigint not null,
property_type varchar(255),
property_id integer not null
);
create table string_property (
id bigint not null,
version bigint,
name varchar(255),
value varchar(255),
primary key (id)
);
create table long_property (
id bigint not null,
version bigint,
name varchar(255),
value bigint,
primary key (id)
);
-
Map - zamiennik strategii ManyToMany i trójskładnikowych związków asocjacyjnych
-
Klucz i wartość klasy Map może być typem prostem , encją lub typem wbudowanym
-
NOTE : Gdy wartość jest encją dodajemy @OneToMany lub @ManyToMany
Note
|
Gdy wartość jest typem prostym lub klasą zagnieżdzoną , dodajemy @ElementCollection |
Warning
|
Map działa tylko po jednej stronie relacji dwukierunkowej |
-
@MapKeyColumn - jeśli kluczem będzie typem bazowym
-
@MapKeyEnumerated - jeśli kluczem będzie enum
@Entity
public class Owner extends AbstractEntity{
@OneToMany
@MapKeyEnumerated(EnumType.STRING)
private Map<BookType, Book> bookMap;
}
-
@MapKeyTemporal -jeśli kluczem będzie typu Data/Calenadar
@Entity
public class Owner extends AbstractEntity{
@OneToMany(mappedBy="owner")
@MapKeyTemporal(TemporalType.TIMESTAMP)
private Map<Date, Book> bookMap;
}
-
@MapKeyJoinColumn - jeśli kluczem mapy będzie encją
-
napisuje JOIN_COLUMN
-
@Entity
public class Owner {
@Id
private long id;
@MapKeyJoinColumn(name="book publisher_id")
private Map<Publisher, Book> bookMap;
}
-
@MapKey
chcemy zdecydować co będzie kluczem w naszej mapie.
-
Dla relacji one-to-many i many-to-many gdzie klucz jest jednym z atrybutów
@Entity
public class Country extends AbstractEntity{
@Column(name="name")
private String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="country_id")
@MapKey(name="id")
private Map<Integer,State> states;
public class Department extends AbstractEntity {
private static final long serialVersionUID = -7670935289254672108L;
private String name;
private Long ids;
@OneToMany(cascade = CascadeType.ALL)
@MapKey
Map<UUID, Phone> phones;
}
-
@MapKeyColumn
public class Department extends AbstractEntity {
private String name;
@ElementCollection
@CollectionTable(name = "subDept")
@MapKeyColumn(name = "subDeptName")
@Column(name = "subDeptShortName")
protected Map<String, String> subDepts = new HashMap<>();
}
-
Sortowanie w pamięci Map i Set
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="bookId")
@SortComparator(BookNameComparator.class)
private SortedSet<Book> books;
...
public class BookNameComparator implements Comparator<Book> {
@Override
public int compare(Book b1, Book b2) {
return b1.getBookName().compareTo(b2.getBookName());
}
}
-
Sortowanie w pamięci Map i Set
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="book_id")
@SortNatural
private SortedSet books;
...
public class Book implements Comparable<Book> {
@Column(name = "writer")
private String writer;
@Override
public int compareTo(Book o) {
return writer.compareTo(o.getWriter());
}
}
Warning
|
W przypadku dużych kolekcji użyć : @OrderBy lub bezpośrednio order by w kwerendzie SQL. |
Manipulowanie operacjami Insert na poziomie encji. Wstawiamy tylko wybrane kolumny.
Note
|
Tuning. Potencjalne przyspieszenie dla dużych tabel w szególności. |
@Entity
@Immutable
@Cache (usage=CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "products")
public class Product extends AbstractEntity {
}
Note
|
@Immutable oznacza , że żadna modyfikacja na 'immutable entity' nie może się udać bez generacji wyjątku. NOTE: Może być stosowana dla kolekcji NOTE: Wyrzucany wyjątek to: HibernateException |
@Entity
@org.hibernate.annotations.Immutable
@org.hibernate.annotations.Subselect(
value = "select i.id as userId, i.firstName as name, " +
"count(a.id) as addressCount " +
"from ITEM i left outer join Address a on i.ID = a.id " +
"group by i.id"
)
@org.hibernate.annotations.Synchronize({"Item", "Bid"})
public class UserAddressStats {
@Id
protected Long userId;
protected String name;
protected long addressCount;
public ItemBidSummary() {
}
}
Note
|
@Synchronize, upewnij się, że encje Item i Bid są 'flushed' przed wykonaniem operacji na ItemBidSummary |
-
Przykład
@Entity
@EntityListeners( LastUpdateListener.class )
public static class Person {
@Id
private Long id;
private String name;
private Date dateOfBirth;
@Transient
private long age;
private Date lastUpdate;
@PostLoad
public void calculateAge() {
age = ChronoUnit.YEARS.between( LocalDateTime.ofInstant(
Instant.ofEpochMilli( dateOfBirth.getTime()), ZoneOffset.UTC),
LocalDateTime.now()
);
}
}
public static class LastUpdateListener {
@PreUpdate
@PrePersist
public void setLastUpdate( Person p ) {
p.setLastUpdate( new Date() );
}
}