我正在寻找Spring Data JPA。考虑下面的例子,我将得到所有的crud和查找器功能默认工作,如果我想自定义一个查找器,那么也可以在界面本身轻松完成。

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

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

我想知道如何添加一个完整的自定义方法及其实现以上AccountRepository?因为它是一个接口,我不能在那里实现方法。


当前回答

我使用下面的代码,以访问生成的查找方法从我的自定义实现。通过bean工厂实现可以防止循环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);
    }
}

其他回答

I扩展了SimpleJpaRepository:

public class ExtendedRepositoryImpl<T extends EntityBean> extends SimpleJpaRepository<T, Long>
    implements ExtendedRepository<T> {

    private final JpaEntityInformation<T, ?> entityInformation;

    private final EntityManager em;

    public ExtendedRepositoryImpl(final JpaEntityInformation<T, ?> entityInformation,
                                                      final EntityManager entityManager) {
       super(entityInformation, entityManager);
       this.entityInformation = entityInformation;
       this.em = entityManager;
    }
}

并将这个类添加到@EnableJpaRepositoryries repositoryBaseClass中。

我使用下面的代码,以访问生成的查找方法从我的自定义实现。通过bean工厂实现可以防止循环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);
    }
}

这里还有一个问题需要考虑。有些人希望将自定义方法添加到存储库中将自动将其作为'/search'链接下的REST服务公开。不幸的是,事实并非如此。Spring目前不支持这一点。

这是“设计”特性,spring data rest显式检查方法是否为自定义方法,并且不会将其作为rest搜索链接公开:

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

这是Oliver Gierke的一段话:

这是有意为之。自定义存储库方法不像查询方法那样 它们可以有效地实现任何行为。因此,它目前是 我们不可能决定HTTP方法来公开方法 下。POST是最安全的选择但这与 泛型查询方法(接收GET)。

欲了解更多详细信息,请参阅此问题:https://jira.spring.io/browse/DATAREST-206

你需要为你的自定义方法创建一个单独的接口:

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() { ... }
}

参见:

4.6 Spring数据存储库的自定义实现 请注意,不同版本之间的命名方案发生了变化。详情见https://stackoverflow.com/a/52624752/66686。

这在使用上是有限的,但是对于简单的自定义方法,你可以使用默认的接口方法,比如:

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将自动为您定义方法。