当使用新的Spring Data Evans版本时,很高兴能够使用java 8附带的一些好东西。其中一个是接口中的默认实现。下面的存储库使用QueryDSL使查询类型安全。
我的问题是,在我写这篇文章之前,我使用了UserRepositoryCustom
的单独findByLogin
接口的模式,然后是另一个类UserRepositoryImpl
,在那个类中,我将拥有{ {1}}获取当前@PersistenceContext
。
如果没有上课,如何获得EntityManager
?它甚至可能吗?
EntityManager
答案 0 :(得分:15)
默认方法只应用于委托对其他存储库方法的调用。默认方法 - 根据定义 - 无法访问实例的任何状态(因为接口没有)。他们只能委托其他接口方法或调用其他类的静态方法。
实际上,使用reference documentation中描述的自定义实现是正确的方法。这是参考的简短版本(如果其他人也想知道):
/**
* Interface for methods you want to implement manually.
*/
interface UserRepositoryCustom {
Optional<User> findByLogin(String login);
}
/**
* Implementation of exactly these methods.
*/
class UserRepositoryImpl extends QueryDslRepositorySupport implements UserRepositoryCustom {
private static final QUser USER = QUser.user;
@Override
public Optional<User> findByLogin(String login) {
return Optional.ofNullable(
from(USER).
where(
USER.deleter.isNull(),
USER.locked.isFalse(),
USER.login.equalsIgnoreCase(login)).
singleResult(USER));
}
}
/**
* The main repository interface extending the custom one so that the manually
* implemented methods get "pulled" into the API.
*/
public interface UserRepository extends UserRepositoryCustom,
CrudRepository<User, Long> { … }
请注意,命名约定在这里很重要(但可以根据需要进行自定义)。通过扩展QueryDslRepositorySupport
,您可以访问from(…)
方法,这样您就不必自己与EntityManager
进行互动。
或者你可以让UserRepository
实现QueryDslPredicateExecutor
并从存储库外部传递谓词,但这会让你最终得到需要使用Querydsl的客户端(这可能是不需要的)加上你没有得到Optional
包装类型OOTB。
答案 1 :(得分:3)
您没有在界面中获得EntityManager
,尽管您可以通过查找来解决它。
但你为什么要这样做呢? Spring Data JPA已经支持Optional
返回类型,因此您无需实现它。 Spring Data将为您完成。
public interface UserRepository extends JpaRepository<User, UUID> {
Optional<User> findByLoginIgnoreCase(String login) {
}
上面的代码应该是您所需要的。如果需要,您甚至可以使用@Query
指定查询。
可以找到样本here。
答案 2 :(得分:0)
我最终做的是创建一个具有getEntityManager()
的存储库库但是,让基类使用spring boot
并不是一件容易的事// DomainRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import javax.persistence.EntityManager;
import java.io.Serializable;
@NoRepositoryBean
public interface DomainRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
EntityManager getEntityManager();
}
然后执行
// DomainRepositoryImpl.java
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import java.io.Serializable;
public class DomainRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements DomainRepository<T, ID> {
private EntityManager entityManager;
public DomainRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
public EntityManager getEntityManager() {
return entityManager;
}
}
但是Spring需要知道如何创建域名存储库,因此我们需要创建一个工厂。
// DomainRepositoryFactoryBean.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
import java.io.Serializable;
public class DomainRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new RepositoryBaseFactory(entityManager);
}
private static class RepositoryBaseFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public RepositoryBaseFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new DomainRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
//to check for QueryDslJpaRepository's which is out of scope.
return DomainRepository.class;
}
}
}
然后告诉spring boot在创建存储库时使用此工厂
// DomainConfig.java
@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = DomainRepositoryFactoryBean.class, basePackages = {"com.mysite.domain"})
@EnableTransactionManagement
public class DomainConfig {
}
然后更改UserRepository以使用它。
@Repository
public interface UserRepository extends DomainRepository<User, UUID> {
public default Optional<User> findByLogin(String login) {
JPAQuery query = new JPAQuery(getEntityManager());
...
}
}