package org.dayatang.persistence.jpa;
import org.dayatang.domain.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 通用仓储接口的JPA实现。
* <p> EntityRepositoryJpa通过EntityManagerProvider获取EntityManager,以保证在当前线程和事务中
* 对数据库的多次访问都是由同一个EntityManager来进行。
* <p>为了根据命名查询的名称获得对应的JPQL,需要提供一个NamedQueryParser。JPA规范没有强制实现这个需求,
* 根据JPA实现的不同,要在IoC容器中配置相应的NamedQueryParser实现。
* @author yyang (<a href="mailto:gdyangyu@gmail.com">gdyangyu@gmail.com</a>)
*/
public class EntityRepositoryJpa implements EntityRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(EntityRepositoryJpa.class);
//命名查询解析器,它是可选的
private NamedQueryParser namedQueryParser;
private EntityManagerProvider entityManagerProvider;
public EntityRepositoryJpa() {
entityManagerProvider = new EntityManagerProvider();
}
public EntityRepositoryJpa(EntityManager entityManager) {
entityManagerProvider = new EntityManagerProvider(entityManager);
}
public EntityRepositoryJpa(EntityManagerFactory entityManagerFactory) {
entityManagerProvider = new EntityManagerProvider(entityManagerFactory);
}
public EntityRepositoryJpa(NamedQueryParser namedQueryParser, EntityManagerFactory entityManagerFactory) {
this(entityManagerFactory);
setNamedQueryParser(namedQueryParser);
}
private NamedQueryParser getNamedQueryParser() {
if (namedQueryParser == null) {
namedQueryParser = InstanceFactory.getInstance(NamedQueryParser.class);
}
namedQueryParser.setEntityManagerProvider(entityManagerProvider);
return namedQueryParser;
}
public final void setNamedQueryParser(NamedQueryParser namedQueryParser) {
namedQueryParser.setEntityManagerProvider(entityManagerProvider);
this.namedQueryParser = namedQueryParser;
}
EntityManager getEntityManager() {
return entityManagerProvider.getEntityManager();
}
@Override
public <T extends Entity> T save(T entity) {
if (entity.notExisted()) {
getEntityManager().persist(entity);
LOGGER.info("create a entity: " + entity.getClass() + "/"
+ entity.getId() + ".");
return entity;
}
T result = getEntityManager().merge(entity);
LOGGER.info("update a entity: " + entity.getClass() + "/"
+ entity.getId() + ".");
return result;
}
/*
* (non-Javadoc)
*
* @see
* org.dayatang.domain.EntityRepository#remove(org.dayatang.domain.Entity)
*/
@Override
public void remove(Entity entity) {
getEntityManager().remove(get(entity.getClass(), entity.getId()));
LOGGER.info("remove a entity: " + entity.getClass() + "/"
+ entity.getId() + ".");
}
/*
* (non-Javadoc)
*
* @see org.dayatang.domain.EntityRepository#exists(java.io.Serializable)
*/
@Override
public <T extends Entity> boolean exists(final Class<T> clazz,
final Serializable id) {
T entity = getEntityManager().find(clazz, id);
return entity != null;
}
/*
* (non-Javadoc)
*
* @see org.dayatang.domain.EntityRepository#get(java.io.Serializable)
*/
@Override
public <T extends Entity> T get(final Class<T> clazz, final Serializable id) {
return getEntityManager().find(clazz, id);
}
/*
* (non-Javadoc)
*
* @see org.dayatang.domain.EntityRepository#load(java.io.Serializable)
*/
@Override
public <T extends Entity> T load(final Class<T> clazz, final Serializable id) {
return getEntityManager().getReference(clazz, id);
}
@Override
public <T extends Entity> T getUnmodified(final Class<T> clazz,
final T entity) {
getEntityManager().detach(entity);
return get(clazz, entity.getId());
}
@Override
public <T extends Entity> T getByBusinessKeys(Class<T> clazz, NamedParameters keyValues) {
List<T> results = findByProperties(clazz, keyValues);
return results.isEmpty() ? null : results.get(0);
}
@Override
public <T extends Entity> List<T> findAll(final Class<T> clazz) {
String queryString = "select o from " + clazz.getName() + " as o";
return getEntityManager().createQuery(queryString).getResultList();
}
@Override
public <T extends Entity> CriteriaQuery createCriteriaQuery(Class<T> entityClass) {
return new CriteriaQuery(this, entityClass);
}
@Override
public <T> List<T> find(CriteriaQuery criteriaQuery) {
Query query = getEntityManager().createQuery(criteriaQuery.getQueryString());
processQuery(query, criteriaQuery.getParameters(),
criteriaQuery.getFirstResult(), criteriaQuery.getMaxResults());
return query.getResultList();
}
@Override
public <T> T getSingleResult(CriteriaQuery criteriaQuery) {
List<T> results = find(criteriaQuery);
return results.isEmpty() ? null : results.get(0);
}
@Override
public <T extends Entity> List<T> find(Class<T> entityClass, QueryCriterion criterion) {
return find(createCriteriaQuery(entityClass).and(criterion));
}
@Override
public <T extends Entity> T getSingleResult(Class<T> entityClass, QueryCriterion criterion) {
return getSingleResult(createCriteriaQuery(entityClass).and(criterion));
}
@Override
public JpqlQuery createJpqlQuery(String jpql) {
return new JpqlQuery(this, jpql);
}
@Override
public <T> List<T> find(JpqlQuery jpqlQuery) {
return getQuery(jpqlQuery).getResultList();
}
@Override
public <T> T getSingleResult(JpqlQuery jpqlQuery) {
try {
return (T) getQuery(jpqlQuery).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
@Override
public int executeUpdate(JpqlQuery jpqlQuery) {
return getQuery(jpqlQuery).executeUpdate();
}
private Query getQuery(JpqlQuery jpqlQuery) {
Query query = getEntityManager().createQuery(jpqlQuery.getJpql());
processQuery(query, jpqlQuery);
return query;
}
@Override
public NamedQuery createNamedQuery(String queryName) {
return new NamedQuery(this, queryName);
}
@Override
public <T> List<T> find(NamedQuery namedQuery) {
return getQuery(namedQuery).getResultList();
}
@Override
public <T> T getSingleResult(NamedQuery namedQuery) {
try {
return (T) getQuery(namedQuery).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
@Override
public int executeUpdate(NamedQuery namedQuery) {
return getQuery(namedQuery).executeUpdate();
}
private Query getQuery(NamedQuery namedQuery) {
Query query = getEntityManager().createNamedQuery(namedQuery.getQueryName());
processQuery(query, namedQuery);
return query;
}
@Override
public SqlQuery createSqlQuery(String sql) {
return new SqlQuery(this, sql);
}
@Override
public <T> List<T> find(SqlQuery sqlQuery) {
return getQuery(sqlQuery).getResultList();
}
@Override
public <T> T getSingleResult(SqlQuery sqlQuery) {
try {
return (T) getQuery(sqlQuery).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
@Override
public int executeUpdate(SqlQuery sqlQuery) {
return getQuery(sqlQuery).executeUpdate();
}
private Query getQuery(SqlQuery sqlQuery) {
Query query;
if (sqlQuery.getResultEntityClass() == null) {
query = getEntityManager().createNativeQuery(sqlQuery.getSql());
} else {
query = getEntityManager().createNativeQuery(sqlQuery.getSql(),
sqlQuery.getResultEntityClass());
}
processQuery(query, sqlQuery);
return query;
}
@Override
public <T extends Entity, E extends T> List<T> findByExample(
final E example, final ExampleSettings<T> settings) {
throw new RuntimeException("not implemented yet!");
}
@Override
public <T extends Entity> List<T> findByProperty(Class<T> clazz, String propertyName, Object propertyValue) {
return find(new CriteriaQuery(this, clazz).eq(propertyName, propertyValue));
}
@Override
public <T extends Entity> List<T> findByProperties(Class<T> clazz, NamedParameters properties) {
CriteriaQuery criteriaQuery = new CriteriaQuery(this, clazz);
for (Map.Entry<String, Object> each : properties.getParams().entrySet()) {
criteriaQuery = criteriaQuery.eq(each.getKey(), each.getValue());
}
return find(criteriaQuery);
}
@Override
public String getQueryStringOfNamedQuery(String queryName) {
return getNamedQueryParser().getQueryStringOfNamedQuery(queryName);
}
@Override
public void flush() {
getEntityManager().flush();
}
@Override
public void refresh(Entity entity) {
getEntityManager().refresh(entity);
}
@Override
public void clear() {
getEntityManager().clear();
}
private void processQuery(Query query, BaseQuery<?> originQuery) {
processQuery(query, originQuery.getParameters(),
originQuery.getFirstResult(), originQuery.getMaxResults());
}
private void processQuery(Query query, QueryParameters parameters,
int firstResult, int maxResults) {
fillParameters(query, parameters);
query.setFirstResult(firstResult);
if (maxResults > 0) {
query.setMaxResults(maxResults);
}
}
private void fillParameters(Query query, QueryParameters params) {
if (params == null) {
return;
}
if (params instanceof PositionalParameters) {
fillParameters(query, (PositionalParameters) params);
} else if (params instanceof NamedParameters) {
fillParameters(query, (NamedParameters) params);
} else {
throw new UnsupportedOperationException("不支持的参数形式");
}
}
private void fillParameters(Query query, PositionalParameters params) {
Object[] paramArray = params.getParams();
for (int i = 0; i < paramArray.length; i++) {
query = query.setParameter(i + 1, paramArray[i]);
}
}
private void fillParameters(Query query, NamedParameters params) {
for (Map.Entry<String, Object> each : params.getParams().entrySet()) {
query = query.setParameter(each.getKey(), each.getValue());
}
}
}