Java Type to JDBC Type
JAVA TYPE |
JDBC TYPE |
java.time.LocalDate |
DATE |
java.time.LocalTime |
TIME |
java.time.LocalDateTime |
TIMESTAMP |
java.time.OffsetTime |
TIME_WITH_TIMEZONE |
java.time.OffsetDateTime |
TIMESTAMP_WITH_TIMEZONE |
java.time.Duration |
BIGINT |
java.time.Instant |
TIMESTAMP |
java.time.ZonedDateTime |
TIMESTAMP |
Changing Persistence Unit dynamically
Keep the persistence unit file (Persistence.xml) as it’s. You can override the properties in it as follows.
1
2
3
4
5
6
7
8
9
10
|
EntityManagerFactory managerFactory = null;
Map<String, String> persistenceMap = new HashMap<String, String>();
persistenceMap.put("javax.persistence.jdbc.url", "<url>");
persistenceMap.put("javax.persistence.jdbc.user", "<username>");
persistenceMap.put("javax.persistence.jdbc.password", "<password>");
persistenceMap.put("javax.persistence.jdbc.driver", "<driver>");
managerFactory = Persistence.createEntityManagerFactory("<current persistence unit>", persistenceMap);
manager = managerFactory.createEntityManager();
|
Bulk update with JPA CriteriaUpdate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public void bulkUpdatePricesInLocal() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaUpdate<ProductEntity> cu = cb.createCriteriaUpdate(ProductEntity.class);
Root<ProductEntity> root = cu.from(ProductEntity.class);
Join<ProductEntity, CurrencyEntity> currencyToConsumer = root.join(ProductEntity_.currencyToConsumer);
Join<ProductEntity, CurrencyEntity> currencyToRetailer = root.join(ProductEntity_.currencyToRetailer);
Expression<BigDecimal> prodConsumer = cb.prod(root.<BigDecimal>get(ProductEntity_.priceToConsumer), currencyToConsumer.<BigDecimal>get(CurrencyEntity_.rateTCMB));
Expression<BigDecimal> prodRetailer = cb.prod(root.<BigDecimal>get(ProductEntity_.priceToRetailer), currencyToRetailer.<BigDecimal>get(CurrencyEntity_.rateTCMB));
cu.set(root.get(ProductEntity_.priceToConsumerInLocal), prodConsumer);
cu.set(root.get(ProductEntity_.priceToRetailerInLocal), prodRetailer);
Query query = em.createQuery(cu);
int resultList = query.executeUpdate();
}
|
Many-many relationship with extra columns in JPA
1
2
3
4
5
6
7
8
9
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
|
@Embeddable
public class DeveloperProjectId implements Serializable {
private Long developerId;
private Long projectId;
// constructor, getters, setters
}
@Entity
public class DeveloperProject implements Serializable {
@EmbeddedId
private DeveloperProjectId developerProjectId;
@ManyToOne
@MapsId("developerId")
private Developer developer;
@ManyToOne
@MapsId("projectId")
private Project project;
@Column
private String task;
// constructor, getters, setters
}
@Entity
public class Developer implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "developer")
private List<DeveloperProject> projects;
// constructor, getters, setters
}
@Entity
public class Project implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column
private String name;
@OneToMany(mappedBy = "project")
private List<DeveloperProject> developers;
// constructor, getters, setters
}
|
CriteriaBuilder join two tables with a custom condition
1
2
3
4
|
CriteriaQuery<A> searchQuery = criteriaBuilder.createQuery(A.class);
Root<A> aRoot = searchQuery.from(A.class);
Join<A, B> bJoin= aRoot.join("mappedB", JoinType.LEFT);
bJoin.on(criteriaBuilder.equal(bJoin.get("idLanguage"), 22));
|
equal to
1
|
LEFT OUTER JOIN B ON A.ID = B.A_ID AND B.idLanguage = 22
|
Json converter
Data model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class MyJson implements Serializable {
private String stringProp;
private Long longProp;
public String getStringProp() {
return stringProp;
}
public void setStringProp(String stringProp) {
this.stringProp = stringProp;
}
public Long getLongProp() {
return longProp;
}
public void setLongProp(Long longProp) {
this.longProp = longProp;
}
}
|
JsonAttributeConverter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@Converter(autoApply = true)
public class JsonAttributeConverter implements AttributeConverter<Object, String> {
private JsonbConfig cfg = new JsonbConfig().withFormatting(true);
private Jsonb jsonb = JsonbBuilder.create(cfg);
@Override
public String convertToDatabaseColumn(Object object) {
if (object == null) {
return null;
}
return jsonb.toJson(object);
}
@Override
public Object convertToEntityAttribute(String value) {
if (value == null) {
return null;
}
return jsonb.fromJson(value, value.getClass());
}
}
|
JPA Entity
1
2
3
4
5
6
7
8
9
10
11
12
|
@Entity
public class TestEntity implements Serializable {
...
@Column(columnDefinition = "JSON")
@Convert(converter = JsonAttributeConverter.class)
private MyJson jsonData;
...
}
|
@Mutable annotation
Ref: @Mutable
Don’t forget to annotate complex fiels with the @Mutable annotation. The change-tracking mechanism only works for non-mutable/basic fields. And thus, no updates were detected.
Example:
1
2
3
4
5
6
7
8
9
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
|
@Column(columnDefinition = "JSON")
@Convert(converter = RehearsalAttributeConverter.class)
@Mutable
private Rehearsal rehearsal;
...
public class Rehearsal implements Serializable {
private List<Product> products;
private Map<Product, Feature> features;
private double shortTermDebt = 0;
...
}
@Converter(autoApply = true)
public class RehearsalAttributeConverter implements AttributeConverter<Rehearsal, String> {
private JsonbConfig cfg = new JsonbConfig().withFormatting(true);
private Jsonb jsonb = JsonbBuilder.create(cfg);
@Override
public String convertToDatabaseColumn(Rehearsal object) {
if (object == null) {
return null;
}
return jsonb.toJson(object, Rehearsal.class);
}
@Override
public Rehearsal convertToEntityAttribute(String value) {
if (value == null) {
return null;
}
return jsonb.fromJson(value, Rehearsal.class);
}
}
|
ElementCollection Map<Integer, Entity>
Association annotated with @ElementCollection
is valid for the following mapping types:
Map<Basic,Basic>
Map<Basic,Embeddable>
Map<Embeddable,Basic>
Map<Embeddable,Embeddable>
Map<Entity,Basic>
Map<Entity,Embeddable>
Association annotated with @OneToMany
/ @ManyToMany
is valid for the following mapping types:
Map<Basic,Entity>
Map<Embeddable,Entity>
Map<Entity,Entity>
Inheritance Mapping
- MappedSuperclass – the parent classes, can’t be entities
- Single Table – The entities from different classes with a common ancestor are placed in a single table.
- Joined Table – Each class has its table, and querying a subclass entity requires joining the tables.
- Table per Class – All the properties of a class are in its table, so no join is required.
MappedSuperclass:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@MappedSuperclass
public class Employee {
@Id
private long id;
private String name;
// constructor, getters, setters
}
@Entity
public class FullTimeEmployee extends Employee {
private int salary;
// constructor, getters, setters
}
@Entity
public class PartTimeEmployee extends Employee {
private int hourlyRate;
// constructor, getters, setters
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
classDiagram
class FullTimeEmployee{
+long id
+String name
+int salary
+getId()
+getName()
+getSalary()
}
class PartTimeEmployee{
+long id
+String name
+int hourlyRate
+getId()
+getName()
+getHourlyRate()
}
|
Single Table:
to differentiate between the records, by default, it is done through a discriminator column called DTYPE
. To customize the discriminator column, we can use the @DiscriminatorColumn
annotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Employee {
@Id
private long id;
private String name;
// constructor, getters, setters
}
@Entity
public class FullTimeEmployee extends Employee {
private int salary;
// constructor, getters, setters
}
@Entity
public class PartTimeEmployee extends Employee {
private int hourlyRate;
// constructor, getters, setters
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
classDiagram
class Employee{
+long id
+int dtype
+String name
+int salary
+int hourlyRate
+getId()
+getName()
+getSalary()
+getHourlyRate()
}
|
Joined Table:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
@Id
private long id;
private String name;
// constructor, getters, setters
}
@Entity
public class FullTimeEmployee extends Employee {
private int salary;
// constructor, getters, setters
}
@Entity
public class PartTimeEmployee extends Employee {
private int hourlyRate;
// constructor, getters, setters
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
classDiagram
Employee <|-- FullTimeEmployee
Employee <|-- PartTimeEmployee
Employee : +long id
Employee : +int dtype
Employee : +String name
Employee: +getId()
Employee: +getName()
class FullTimeEmployee{
+int salary
+getSalary()
}
class PartTimeEmployee{
+int hourlyRate
+getHourlyRate()
}
|
Table per Class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
@Id
private long id;
private String name;
// constructor, getters, setters
}
@Entity
public class FullTimeEmployee extends Employee {
private int salary;
// constructor, getters, setters
}
@Entity
public class PartTimeEmployee extends Employee {
private int hourlyRate;
// constructor, getters, setters
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
classDiagram
Employee <|-- FullTimeEmployee
Employee <|-- PartTimeEmployee
Employee : +long id
Employee : +int dtype
Employee : +String name
Employee: +getId()
Employee: +getName()
class FullTimeEmployee{
+int salary
+getSalary()
}
class PartTimeEmployee{
+int hourlyRate
+getHourlyRate()
}
|