Jak dodać niestandardową metodę do Spring Data JPA

[[1]}Szukam Spring Data JPA. Rozważ poniższy przykład, w którym wszystkie funkcje crud i Findera będą działać domyślnie, a jeśli chcę dostosować finder, to można to łatwo zrobić również w samym interfejsie.

@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {

  @Query("<JPQ statement here>")
  List<Account> findByCustomer(Customer customer);
}

Chciałbym się dowiedzieć, jak Mogę dodać kompletną metodę niestandardową z jej implementacją dla powyższego AccountRepository? Ponieważ jest to interfejs, nie mogę zaimplementować tej metody.

Author: gresdiplitude, 2012-08-09

8 answers

Musisz utworzyć osobny interfejs dla własnych metod:

public interface AccountRepository 
    extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }

public interface AccountRepositoryCustom {
    public void customMethod();
}

I podaj klasę implementacji dla tego interfejsu:

public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @Autowired
    AccountRepository accountRepository;  /* Optional - if you need it */

    public void customMethod() { ... }
}

Zobacz też:

 204
Author: axtavt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-05 19:07:38

Oprócz odpowiedzi axtavt , nie zapomnij, że możesz wprowadzić Entity Manager w swojej niestandardowej implementacji, jeśli potrzebujesz go do budowania zapytań:

public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @PersistenceContext
    private EntityManager em;

    public void customMethod() { 
        ...
        em.createQuery(yourCriteria);
        ...
    }
}
 64
Author: jelies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:39

Jest to ograniczone w użyciu, ale dla prostych metod niestandardowych można użyć domyślnych metod interfejsu, takich jak:

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", "[email protected]", 679856885, "Rzeszów", "Podkarpackie", "35-061", "Zamknięta 12"),
            new Customer("Adrian", "Mularczyk", "[email protected]", 867569344, "Krosno", "Podkarpackie", "32-442", "Hynka 3/16"),
            new Customer("Kazimierz", "Dejna", "[email protected]", 996435876, "Jarosław", "Podkarpackie", "25-122", "Korotyńskiego 11"),
            new Customer("Celina", "Dykiel", "[email protected]", 947845734, "Żywiec", "Śląskie", "54-333", "Polna 29")
        };

        for (Customer customer : customers) {
            save(customer);
        }
    }
}

EDIT:

W tej wiosny tutorial jest napisany:

Spring Data JPA umożliwia również definiowanie innych metod zapytań za pomocą po prostu deklarując swój podpis metody.

Więc możliwe jest nawet zadeklarowanie metody w stylu:

Customer findByHobby(Hobby personHobby);

I jeśli obiekt Hobby jest własnością Klienta, To Spring automatycznie zdefiniuj metodę dla siebie.

 10
Author: Tomasz Mularczyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-24 21:27:48

Używam poniższego kodu, aby uzyskać dostęp do wygenerowanych metod wyszukiwania z mojej niestandardowej implementacji. Wdrożenie w fabryce fasoli zapobiega problemom z tworzeniem fasoli okrągłej.

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);
    }
}
 5
Author: Peter Rietzler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 05:13:47

Biorąc pod uwagę Twój fragment kodu, pamiętaj, że możesz przekazać tylko natywne obiekty do metody findBy###, powiedzmy, że chcesz załadować listę kont, które należą do niektórych klientów, jednym z rozwiązań jest to,

 @Query("Select a from Account a where a."#nameoffield"=?1")
      List<Account> findByCustomer(String "#nameoffield");

Niech sue nazwa tabeli, która ma być zapytana, będzie nazwą klasy encji. Aby uzyskać dalsze implementacje, zapoznaj się z this

 4
Author: samba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-18 08:48:16

Jeśli chcesz być w stanie wykonywać bardziej zaawansowane operacje, możesz potrzebować dostępu do wewnętrznych danych Spring Data, w takim przypadku następujące działania (jako moje tymczasowe rozwiązanie do 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);
        }
    }

}
 3
Author: NealeU,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 15:16:29

Jest jeszcze jedna kwestia, którą należy rozważyć. Niektórzy oczekują, że dodanie niestandardowej metody do repozytorium automatycznie wyświetli je jako usługi REST pod linkiem' / search'. Niestety tak nie jest. Wiosna tego obecnie nie wspiera.

Jest to funkcja 'by design', Spring data rest jawnie sprawdza, czy metoda jest metodą niestandardową i nie wyświetla jej jako link wyszukiwania REST:

private boolean isQueryMethodCandidate(Method method) {    
  return isQueryAnnotationPresentOn(method) || !isCustomMethod(method) && !isBaseClassMethod(method);
}

To jest qoute Olivera Gierke:

To jest przez design. Niestandardowe metody repozytorium nie są metodami zapytań, jak mogą skutecznie realizować każde zachowanie. Tak więc obecnie niemożliwe jest dla nas podjęcie decyzji o metodzie HTTP, aby wyeksponować metodę pod. POST byłby najbezpieczniejszą opcją, ale nie jest to zgodne z ogólne metody zapytań (które otrzymują GET).

Więcej szczegółów znajdziesz w tym numerze: https://jira.spring.io/browse/DATAREST-206

 3
Author: Lukasz Magiera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-21 08:35:03

Przyjęta odpowiedź działa, ale ma trzy problemy:

  • używa nieudokumentowanej funkcji Spring Data podczas nazywania niestandardowej implementacji jako AccountRepositoryImpl. Dokumentacja wyraźnie stwierdza, że musi być wywołana AccountRepositoryCustomImpl, niestandardowa nazwa interfejsu plus Impl
  • nie można używać constructor injection, tylko @Autowired, które są uważane za złe praktyki
  • wewnątrz niestandardowej implementacji masz kolistą zależność (dlatego nie możesz użyć konstruktora wstrzyknięcie).

Znalazłem sposób, aby uczynić go idealnym, choć nie bez użycia innej nieudokumentowanej funkcji danych źródłowych: {]}

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
    }
}
 2
Author: Danila Piatov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-30 22:38:03