Hibernate: Difference between revisions

From Chorke Wiki
Jump to navigation Jump to search
No edit summary
 
(41 intermediate revisions by the same user not shown)
Line 1: Line 1:
* [https://vladmihalcea.com/why-you-should-never-use-the-table-identifier-generator-with-jpa-and-hibernate/ Never use the TABLE identifier generator]
==Replacements==
java.util.Date    => java.time.Instant
java.sql.Timestamp => java.time.Instant
java.sql.Date      => java.time.LocalDate
java.sql.Time      => java.time.LocalTime
 
The Instant class represents a moment on the timeline in '''UTC''' with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC.
 
==Sequence Style==
<source lang="java">
@Id
@Column(name = "code", length = 6)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "page_sqn")
//@SequenceGenerator(name = "page_sqn", sequenceName = "page_sqn", initialValue = 60466176, allocationSize = 1)
@GenericGenerator(name  = "page_sqn", strategy = "org.chorke.academia.core.entity.Base36Style", parameters = {
    @Parameter(name = Base36Style.INITIAL_VALUE,  value = Base36Style.DIGIT_6_MIN),
    @Parameter(name = Base36Style.SEQUENCE_NAME,  value = "page_sqn"),
    @Parameter(name = Base36Style.ALLOCATION_SIZE, value = "1"),
})
private String code;
</source>
 
<source lang="java" highlight="15-17,34,41">
package org.chorke.academia.core.entity;
 
import java.io.Serializable;
import java.util.Properties;
 
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
 
public class Base36Style extends SequenceStyleGenerator {
    private static final Logger LOG = LoggerFactory.getLogger(Base36Style.class);
    public static final String ALLOCATION_SIZE = INCREMENT_PARAM;
    public static final String SEQUENCE_NAME  = SEQUENCE_PARAM;
    public static final String INITIAL_VALUE  = INITIAL_PARAM;
    public static final int    RADIX = 36;
 
    public static final String DIGIT_1_MIN = "0";              //            0 =>            Z
    public static final String DIGIT_2_MIN = "36";              //          10 =>            ZZ
    public static final String DIGIT_3_MIN = "1296";            //          100 =>          ZZZ
    public static final String DIGIT_4_MIN = "46656";          //        1,000 =>        Z,ZZZ
    public static final String DIGIT_5_MIN = "1679616";        //      10,000 =>        ZZ,ZZZ
    public static final String DIGIT_6_MIN = "60466176";        //      100,000 =>      ZZZ,ZZZ
    public static final String DIGIT_7_MIN = "2176782336";      //    1,000,000 =>    Z,ZZZ,ZZZ
    public static final String DIGIT_8_MIN = "78364164096";    //  10,000,000 =>    ZZ,ZZZ,ZZZ
    public static final String DIGIT_9_MIN = "2821109907456";  //  100,000,000 =>  ZZZ,ZZZ,ZZZ
    public static final String DIGIT_X_MIN = "101559956668416"; //1,000,000,000 => Z,ZZZ,ZZZ,ZZZ
 
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        Serializable nextval = super.generate(session, object);
        String base36 = Long.toString((Long) nextval, RADIX);
        LOG.debug("Base36: {}", base36.toUpperCase());
        return base36.toUpperCase();
    }
 
    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        super.configure(LongType.INSTANCE, params, serviceRegistry);
    }
}
</source>
 
==Challenges==
{| class="wikitable sortable"
|-
! Database !! Auto Increment !! Sequence !! Usable
|-
! DB2/LUW
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! DB2/z
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! PostgreSQL
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! Derby
| <code>✕</code> || <code>✓</code> || <code>✓</code>
|-
! Firebird
| <code>✕</code> || <code>✓</code> || <code>✓</code>
|-
! H2
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! HyperSQL
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! INGRES
| <code>✓</code> || <code>✕</code> || <code>✕</code>
|-
! Informix
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|-
! MariaDB
| <code>✓</code> || <code>✕</code> || <code>✕</code>
|-
! MySQL
| <code>✓</code> || <code>✕</code> || <code>✕</code>
|-
! Oracle
| <code>✕</code> || <code>✓</code> || <code>✓</code>
|-
! Sql Server
| <code>✕</code> || <code>✓</code> || <code>✓</code>
|-
! SQLite
| <code>✓</code> || <code>✕</code> || <code>✕</code>
|-
! Sybase
| <code>✓</code> || <code>✕</code> || <code>✕</code>
|-
! Sybase Anywhere
| <code>✓</code> || <code>✓</code> || <code>✓</code>
|}
 
==Date Time==
<source lang="java">
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
 
class Playground {
    public static void main(String[ ] args) {
        System.out.println("Yesterday Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusNanos(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusDays(1L).minusNanos(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusHours(24).minusNanos(1L));
 
        System.out.println();
        System.out.println("Today    Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS));
        System.out.println("Today    Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L).minusNanos(1L));
        System.out.println("Today    Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(24).minusNanos(1L));
 
        System.out.println();
        System.out.println("Tomorrow Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L));
        System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(2L).minusNanos(1L));
        System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(48).minusNanos(1L));
    }
}
</source>
 
==Knowledge==
{|
| valign="top" colspan="2" |
<source lang='java'>
import org.hibernate.Session;
 
Session session = (Session) entityManager.getDelegate();
Page<Country> countries = countryRepo.findAll(page);
countries = countries.map(country -> {
    session.evict(country);
    if (ObjectUtils.isEmpty(country.getContinent())) {
        Continent continent = continentRepo.findById(country.getContinentCode());
        country.setContinent(continent);
        return country;
    } else return country;
});
</source>
 
|-
| colspan="2" |
----
|-
| valign="top" colspan="2" |
<source lang='java'>
@PersistenceContext
EntityManager entityManager;
 
if (entityManager.contains(country)) entityManager.detach(country);
//  entityManager.detach(country);
</source>
 
|-
| colspan="2" |
----
|-
| valign="top" |
 
| valign="top" |
 
|}
 
==References==
{|
| valign="top" |
* [https://stackoverflow.com/questions/24650186 Choosing between <code>java.util.Date</code> or <code>java.sql.Date</code>]
* [https://www.baeldung.com/hibernate-identifiers An Overview of Identifiers in Hibernate]
* [https://www.baeldung.com/hibernate-identifiers An Overview of Identifiers in Hibernate]
* [https://howtodoinjava.com/hibernate/immutable-and-naturalid-hibernate-specific-annotations/ Immutable and NaturalId Annotations]
* [https://howtodoinjava.com/hibernate/immutable-and-naturalid-hibernate-specific-annotations/ Immutable and NaturalId Annotations]
* [https://stackoverflow.com/questions/31158509 Custom Id Generator using Hibernate]
* [[Convention for Database Tables]]
* [https://en.wikibooks.org/wiki/Java_Persistence/Inheritance Java Persistence/Inheritance]
* [https://en.wikibooks.org/wiki/Java_Persistence/Inheritance Java Persistence/Inheritance]
* [https://stackoverflow.com/questions/47259048 How to generate Custom Id]
* [https://stackoverflow.com/questions/47259048 How to generate Custom Id]
* [https://howtodoinjava.com/hibernate/hibernate-naturalid-example-tutorial/ NaturalId Example Tutorial]
* [https://howtodoinjava.com/hibernate/hibernate-naturalid-example-tutorial/ NaturalId Example Tutorial]
* [https://dzone.com/articles/how-to-use-hibernate-natural-ids-in-spring-boot Natural IDs in Spring Boot]
* [https://dzone.com/articles/how-to-use-hibernate-natural-ids-in-spring-boot Natural IDs in Spring Boot]
* [[EclipseLink]]
| valign="top" |
* [https://programmer.group/oracle-to-mysql-database-migration-primary-key-generation-policy-replacement.html Using MySQL table to simulate Oracle Sequence]
* [https://stackoverflow.com/questions/28539915/ Multiple SequenceGenerator in Hibernate Entity]
* [https://coderanch.com/t/573996/databases/SequenceGenerator-MySql-Database <code>@SequenceGenerator</code> for MySql Database]
* [https://vladmihalcea.com/why-you-should-never-use-the-table-identifier-generator-with-jpa-and-hibernate/ Never use the TABLE identifier generator]
* [https://thorben-janssen.com/custom-sequence-based-idgenerator/ Custom Sequence Based ID Generator]
* [https://docs.liquibase.com/change-types/community/create-sequence.html#:~:text=Database%20support Create Sequence Supported Database]
* [https://docs.liquibase.com/change-types/community/add-auto-increment.html#:~:text=Database%20support Auto Increment Supported Database]
* [https://stackoverflow.com/questions/27690709/ JPA Primary Key Prefix]
* [http://www.dbunit.org/howto.html DBUnit]
* [http://www.dbunit.org/howto.html DBUnit]
* [[Locale]]
|}
----
{|
| valign="top" |
* [https://stackoverflow.com/questions/13370221/ PersistentObjectException: detached entity thrown by JPA]
* [https://stackoverflow.com/questions/21708339/ Prevent Jackson to Serialize <code>Non-Fetched Lazy</code> Objects]
* [https://stackoverflow.com/questions/57168773/ Does JPA delete also remove large objects of Blob fields]
* [https://stackoverflow.com/questions/31446/ Detach an entity from JPA/EJB3 persistence context]
* [https://www.baeldung.com/spring-data-jpa-stored-procedures Calling Stored Procedures from Spring Data JPA]
* [https://vladmihalcea.com/ Vlad Mihalcea the Java Champion]
* [https://github.com/eugenp/tutorials/blob/master/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/storedprocedure/repository/CarRepository.java Example of Stored Procedure]
* [[MapStruct]]
* [[Liquibase]]
| valign="top" |
* [https://stackoverflow.com/questions/45973070/ Spring JPA ExampleMatcher compare date condition]
* [https://stackoverflow.com/questions/60112439 Difference btn. <code>evict</code> and <code>detach</code> in hibernate]
* [https://stackoverflow.com/questions/65478350/ Column type is JSON but expression is Varchar]
* [https://stackoverflow.com/questions/39620317/ Map a JSON column with H2 & Spring JPA]
* [https://stackoverflow.com/questions/2311125/ Ignore Hibernate <code>@Where</code> annotation]
* [https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html Java » ISO <code>DateTimeFormatter</code>]
* [https://stackoverflow.com/questions/7700071/  Use  <code>@Where</code> in Hibernate]
* [[Lombok]]
|}

Latest revision as of 18:05, 1 February 2024

Replacements

java.util.Date     => java.time.Instant
java.sql.Timestamp => java.time.Instant
java.sql.Date      => java.time.LocalDate
java.sql.Time      => java.time.LocalTime

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC.

Sequence Style

@Id
@Column(name = "code", length = 6)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "page_sqn")
//@SequenceGenerator(name = "page_sqn", sequenceName = "page_sqn", initialValue = 60466176, allocationSize = 1)
@GenericGenerator(name  = "page_sqn", strategy = "org.chorke.academia.core.entity.Base36Style", parameters = {
    @Parameter(name = Base36Style.INITIAL_VALUE,   value = Base36Style.DIGIT_6_MIN),
    @Parameter(name = Base36Style.SEQUENCE_NAME,   value = "page_sqn"),
    @Parameter(name = Base36Style.ALLOCATION_SIZE, value = "1"),
})
private String code;
package org.chorke.academia.core.entity;

import java.io.Serializable;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;

public class Base36Style extends SequenceStyleGenerator {
    private static final Logger LOG = LoggerFactory.getLogger(Base36Style.class);
    public static final String ALLOCATION_SIZE = INCREMENT_PARAM;
    public static final String SEQUENCE_NAME   = SEQUENCE_PARAM;
    public static final String INITIAL_VALUE   = INITIAL_PARAM;
    public static final int    RADIX = 36;

    public static final String DIGIT_1_MIN = "0";               //            0 =>             Z
    public static final String DIGIT_2_MIN = "36";              //           10 =>            ZZ
    public static final String DIGIT_3_MIN = "1296";            //          100 =>           ZZZ
    public static final String DIGIT_4_MIN = "46656";           //        1,000 =>         Z,ZZZ
    public static final String DIGIT_5_MIN = "1679616";         //       10,000 =>        ZZ,ZZZ
    public static final String DIGIT_6_MIN = "60466176";        //      100,000 =>       ZZZ,ZZZ
    public static final String DIGIT_7_MIN = "2176782336";      //    1,000,000 =>     Z,ZZZ,ZZZ
    public static final String DIGIT_8_MIN = "78364164096";     //   10,000,000 =>    ZZ,ZZZ,ZZZ
    public static final String DIGIT_9_MIN = "2821109907456";   //  100,000,000 =>   ZZZ,ZZZ,ZZZ
    public static final String DIGIT_X_MIN = "101559956668416"; //1,000,000,000 => Z,ZZZ,ZZZ,ZZZ

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        Serializable nextval = super.generate(session, object);
        String base36 = Long.toString((Long) nextval, RADIX);
        LOG.debug("Base36: {}", base36.toUpperCase());
        return base36.toUpperCase();
    }

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        super.configure(LongType.INSTANCE, params, serviceRegistry);
    }
}

Challenges

Database Auto Increment Sequence Usable
DB2/LUW
DB2/z
PostgreSQL
Derby
Firebird
H2
HyperSQL
INGRES
Informix
MariaDB
MySQL
Oracle
Sql Server
SQLite
Sybase
Sybase Anywhere

Date Time

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

class Playground {
    public static void main(String[ ] args) {
        System.out.println("Yesterday Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusNanos(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusDays(1L).minusNanos(1L));
        System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusHours(24).minusNanos(1L));

        System.out.println();
        System.out.println("Today    Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS));
        System.out.println("Today    Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L).minusNanos(1L));
        System.out.println("Today    Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(24).minusNanos(1L));

        System.out.println();
        System.out.println("Tomorrow Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L));
        System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(2L).minusNanos(1L));
        System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(48).minusNanos(1L));
    }
}

Knowledge

import org.hibernate.Session;

Session session = (Session) entityManager.getDelegate();
Page<Country> countries = countryRepo.findAll(page);
countries = countries.map(country -> {
    session.evict(country);
    if (ObjectUtils.isEmpty(country.getContinent())) {
        Continent continent = continentRepo.findById(country.getContinentCode());
        country.setContinent(continent);
        return country;
    } else return country;
});

@PersistenceContext
EntityManager entityManager;

if (entityManager.contains(country)) entityManager.detach(country);
//  entityManager.detach(country);

References