All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.hypersistence.utils.spring.repository.BaseJpaRepositoryImpl Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
package io.hypersistence.utils.spring.repository;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;

import io.hypersistence.utils.hibernate.util.ReflectionUtils;
import org.hibernate.Session;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * @author Vlad Mihalcea
 */
public class BaseJpaRepositoryImpl extends SimpleJpaRepository
    implements BaseJpaRepository {

    private static final String ID_MUST_NOT_BE_NULL = ReflectionUtils.getFieldValueOrNull(SimpleJpaRepository.class, "ID_MUST_NOT_BE_NULL");

    private final EntityManager entityManager;
    private final JpaEntityInformation entityInformation;

    public BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityInformation = entityInformation;
        this.entityManager = entityManager;
    }

    @Transactional
    public  S persist(S entity) {
        entityManager.persist(entity);
        return entity;
    }

    @Transactional
    public  S persistAndFlush(S entity) {
        persist(entity);
        entityManager.flush();
        return entity;
    }

    @Transactional
    public  List persistAll(Iterable entities) {
        List result = new ArrayList<>();
        for(S entity : entities) {
            result.add(persist(entity));
        }
        return result;
    }

    @Transactional
    public  List persistAllAndFlush(Iterable entities) {
        return executeBatch(() -> {
            List result = new ArrayList<>();
            for(S entity : entities) {
                result.add(persist(entity));
            }
            entityManager.flush();
            return result;
        });
    }

    @Transactional
    public  S merge(S entity) {
        return entityManager.merge(entity);
    }

    @Transactional
    public  S mergeAndFlush(S entity) {
        S result = merge(entity);
        entityManager.flush();
        return result;
    }

    @Transactional
    public  List mergeAll(Iterable entities) {
        List result = new ArrayList<>();
        for(S entity : entities) {
            result.add(merge(entity));
        }
        return result;
    }

    @Transactional
    public  List mergeAllAndFlush(Iterable entities) {
        return executeBatch(() -> {
            List result = new ArrayList<>();
            for(S entity : entities) {
                result.add(merge(entity));
            }
            entityManager.flush();
            return result;
        });
    }

    @Transactional
    public  S update(S entity) {
        session().update(entity);
        return entity;
    }

    @Transactional
    public  S updateAndFlush(S entity) {
        update(entity);
        entityManager.flush();
        return entity;
    }

    @Transactional
    public  List updateAll(Iterable entities) {
        List result = new ArrayList<>();
        for(S entity : entities) {
            result.add(update(entity));
        }
        return result;
    }

    @Transactional
    public  List updateAllAndFlush(Iterable entities) {
        return executeBatch(() -> {
            List result = new ArrayList<>();
            for(S entity : entities) {
                result.add(update(entity));
            }
            entityManager.flush();
            return result;
        });
    }

    @Override
    public T getReferenceById(ID id) {
        Assert.notNull(id, ID_MUST_NOT_BE_NULL);
        return entityManager.getReference(getDomainClass(), id);
    }

    @Override
    public T lockById(ID id, LockModeType lockMode) {
        return (T) entityManager.find(entityInformation.getJavaType(), id, lockMode);
    }

    protected Integer getBatchSize(Session session) {
        SessionFactoryImplementor sessionFactory = session.getSessionFactory().unwrap(SessionFactoryImplementor.class);
        final JdbcServices jdbcServices = sessionFactory.getServiceRegistry().getService(JdbcServices.class);
        if(!jdbcServices.getExtractedMetaDataSupport().supportsBatchUpdates()) {
            return Integer.MIN_VALUE;
        }
        return session.unwrap(AbstractSharedSessionContract.class).getConfiguredJdbcBatchSize();
    }

    protected  R executeBatch(Supplier callback) {
        Session session = session();
        Integer jdbcBatchSize = getBatchSize(session);
        Integer originalSessionBatchSize = session.getJdbcBatchSize();
        try {
            if (jdbcBatchSize == null) {
                session.setJdbcBatchSize(10);
            }
            return callback.get();
        } finally {
            session.setJdbcBatchSize(originalSessionBatchSize);
        }
    }

    protected Session session() {
        return entityManager.unwrap(Session.class);
    }
}