Spring Data JPA를 찾고 있습니다. 기본적으로 모든 크루 드 및 파인더 기능이 작동하는 아래 예제를 고려하고 파인더를 사용자 정의하려면 인터페이스 자체에서 쉽게 수행 할 수 있습니다.
@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {
@Query("<JPQ statement here>")
List<Account> findByCustomer(Customer customer);
}
위의 AccountRepository에 대한 구현으로 완전한 사용자 정의 메소드를 추가하는 방법을 알고 싶습니다. 인터페이스 때문에 메소드를 구현할 수 없습니다.
답변
사용자 정의 메소드에 대해 별도의 인터페이스를 작성해야합니다.
public interface AccountRepository
extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }
public interface AccountRepositoryCustom {
public void customMethod();
}
해당 인터페이스에 대한 구현 클래스를 제공하십시오.
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@Autowired
@Lazy
AccountRepository accountRepository; /* Optional - if you need it */
public void customMethod() { ... }
}
또한보십시오:
-
이름 지정 체계는 버전간에 변경되었습니다. 자세한 내용은 https://stackoverflow.com/a/52624752/66686 을 참조하십시오.
답변
axtavt의 답변 외에도 쿼리를 작성하는 데 필요한 경우 사용자 정의 구현에 Entity Manager를 삽입 할 수 있음을 잊지 마십시오.
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@PersistenceContext
private EntityManager em;
public void customMethod() {
...
em.createQuery(yourCriteria);
...
}
}
답변
수락 된 답변은 효과가 있지만 세 가지 문제가 있습니다.
- 커스텀 구현을로 명명 할 때 문서화되지 않은 스프링 데이터 기능을 사용합니다
AccountRepositoryImpl
. 문서는 명확하게 호출 할 것을 명시AccountRepositoryCustomImpl
, 사용자 정의 인터페이스 이름과Impl
@Autowired
나쁜 습관으로 간주되는 생성자 주입 만 사용할 수 없습니다.- 사용자 정의 구현 내부에 순환 종속성이 있습니다 (따라서 생성자 삽입을 사용할 수 없습니다).
문서화되지 않은 다른 스프링 데이터 기능을 사용하지 않고도 완벽하게 만드는 방법을 찾았습니다.
public interface AccountRepository extends AccountRepositoryBasic,
AccountRepositoryCustom
{
}
public interface AccountRepositoryBasic extends JpaRepository<Account, Long>
{
// standard Spring Data methods, like findByLogin
}
public interface AccountRepositoryCustom
{
public void customMethod();
}
public class AccountRepositoryCustomImpl implements AccountRepositoryCustom
{
private final AccountRepositoryBasic accountRepositoryBasic;
// constructor-based injection
public AccountRepositoryCustomImpl(
AccountRepositoryBasic accountRepositoryBasic)
{
this.accountRepositoryBasic = accountRepositoryBasic;
}
public void customMethod()
{
// we can call all basic Spring Data methods using
// accountRepositoryBasic
}
}
답변
사용에는 제한이 있지만 간단한 사용자 정의 메소드의 경우 다음 과 같은 기본 인터페이스 메소드를 사용할 수 있습니다 .
import demo.database.Customer;
import org.springframework.data.repository.CrudRepository;
public interface CustomerService extends CrudRepository<Customer, Long> {
default void addSomeCustomers() {
Customer[] customers = {
new Customer("Józef", "Nowak", "nowakJ@o2.pl", 679856885, "Rzeszów", "Podkarpackie", "35-061", "Zamknięta 12"),
new Customer("Adrian", "Mularczyk", "adii333@wp.pl", 867569344, "Krosno", "Podkarpackie", "32-442", "Hynka 3/16"),
new Customer("Kazimierz", "Dejna", "sobieski22@weebly.com", 996435876, "Jarosław", "Podkarpackie", "25-122", "Korotyńskiego 11"),
new Customer("Celina", "Dykiel", "celina.dykiel39@yahoo.org", 947845734, "Żywiec", "Śląskie", "54-333", "Polna 29")
};
for (Customer customer : customers) {
save(customer);
}
}
}
편집하다:
Spring Data JPA를 사용하면 메소드 서명을 선언하여 다른 쿼리 메소드를 정의 할 수도 있습니다.
따라서 다음과 같은 메소드를 선언하는 것조차 가능합니다.
Customer findByHobby(Hobby personHobby);
객체 Hobby
가 Customer의 속성이라면 Spring은 자동으로 메소드를 정의합니다.
답변
내 사용자 정의 구현에서 생성 된 찾기 메소드에 액세스하기 위해 다음 코드를 사용하고 있습니다. Bean Factory를 통해 구현하면 순환 Bean 작성 문제가 방지됩니다.
public class MyRepositoryImpl implements MyRepositoryExtensions, BeanFactoryAware {
private BrandRepository myRepository;
public MyBean findOne(int first, int second) {
return myRepository.findOne(new Id(first, second));
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
myRepository = beanFactory.getBean(MyRepository.class);
}
}
답변
문서화 된 기능 에 Impl
명시된 바와 같이 접미사를 사용하면 다음과 같이 깨끗한 솔루션을 얻을 수 있습니다.
- 에 정의
@Repository
말하자면, 인터페이스MyEntityRepository
방법 또는 사용자 정의 방법을 어느 봄 데이터 - 커스텀 메소드 만 구현 하는 클래스
MyEntityRepositoryImpl
(Impl
접미사는 마술 임)를 작성 하고 ** ( 작동 하지 않음 )로 클래스에 주석을 달십시오 .@Component
@Repository
- 이 클래스도 삽입 할 수
MyEntityRepository
를 통해@Autowired
사용자 정의 방법에 사용합니다.
- 이 클래스도 삽입 할 수
예:
엔터티 클래스 :
package myapp.domain.myentity;
@Entity
public class MyEntity {
@Id
private Long id;
@Column
private String comment;
}
리포지토리 인터페이스 :
package myapp.domain.myentity;
@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
// EXAMPLE SPRING DATA METHOD
List<MyEntity> findByCommentEndsWith(String x);
List<MyEntity> doSomeHql(Long id);
List<MyEntity> useTheRepo(Long id);
}
사용자 정의 메소드 구현 Bean :
package myapp.infrastructure.myentity;
@Component // Must be @Component !!
public class MyEntityRepositoryImpl { // must have the repo name + Impl !!
@PersistenceContext
private EntityManager entityManager;
@Autowired
private MyEntityRepository myEntityRepository;
@SuppressWarnings("unused")
public List<MyEntity> doSomeHql(Long id) {
String hql = "SELECT eFROM MyEntity e WHERE e.id = :id";
TypedQuery<MyEntity> query = entityManager.createQuery(hql, MyEntity.class);
query.setParameter("id", id);
return query.getResultList();
}
@SuppressWarnings("unused")
public List<MyEntity> useTheRepo(Long id) {
List<MyEntity> es = doSomeHql(id);
es.addAll(myEntityRepository.findByCommentEndsWith("DO"));
es.add(myEntityRepository.findById(2L).get());
return es;
}
}
내가 확인한 작은 단점은 다음과 같습니다.
답변
좀 더 정교한 작업을 수행하려면 Spring Data의 내부에 액세스해야 할 수 있습니다.이 경우 DATAJPA-422에 대한 임시 솔루션으로 다음과 같이 작동합니다 .
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
private JpaEntityInformation<Account, ?> entityInformation;
@PostConstruct
public void postConstruct() {
this.entityInformation = JpaEntityInformationSupport.getMetadata(Account.class, entityManager);
}
@Override
@Transactional
public Account saveWithReferenceToOrganisation(Account entity, long referralId) {
entity.setOrganisation(entityManager.getReference(Organisation.class, organisationId));
return save(entity);
}
private Account save(Account entity) {
// save in same way as SimpleJpaRepository
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
}