Sha*_*dav 144 java spring-data spring-data-jpa
我正在研究Spring Data JPA.考虑下面的示例,我将默认使用所有crud和finder功能,如果我想自定义查找器,那么也可以在界面本身轻松完成.
@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {
@Query("<JPQ statement here>")
List<Account> findByCustomer(Customer customer);
}
Run Code Online (Sandbox Code Playgroud)
我想知道如何为上述AccountRepository添加一个完整的自定义方法及其实现?由于它的接口我无法在那里实现该方法.
axt*_*avt 265
您需要为自定义方法创建单独的界面:
public interface AccountRepository
extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }
public interface AccountRepositoryCustom {
public void customMethod();
}
Run Code Online (Sandbox Code Playgroud)
并为该接口提供实现类:
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@Autowired
@Lazy
AccountRepository accountRepository; /* Optional - if you need it */
public void customMethod() { ... }
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
请注意,命名方案在不同版本之间已更改.有关详细信息,请参阅/sf/answers/3683732671/.
jel*_*ies 68
除了axtavt的答案之外,请不要忘记,如果您需要构建查询,可以在自定义实现中注入Entity Manager:
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@PersistenceContext
private EntityManager em;
public void customMethod() {
...
em.createQuery(yourCriteria);
...
}
}
Run Code Online (Sandbox Code Playgroud)
acd*_*ior 16
有一个稍微修改的解决方案,不需要额外的接口。
正如文档功能中所述,Impl
后缀允许我们拥有这样干净的解决方案:
@Repository
接口MyEntityRepository
中定义自定义方法(除了您的 Spring Data 方法)MyEntityRepositoryImpl
(该Impl
后缀是魔法)的任何地方(甚至不必是在同一个包),其实现自定义的方法只和注释等类@Component
**(@Repository
不会工作)。
MyEntityRepository
via@Autowired
以在自定义方法中使用。实体类(为了完整性):
package myapp.domain.myentity;
@Entity
public class MyEntity {
@Id private Long id;
@Column private String comment;
}
Run Code Online (Sandbox Code Playgroud)
仓库接口:
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); // custom method, code at *Impl class below
List<MyEntity> useTheRepo(Long id); // custom method, code at *Impl class below
}
Run Code Online (Sandbox Code Playgroud)
自定义方法实现 bean:
package myapp.infrastructure.myentity;
@Component // Must be @Component !!
public class MyEntityRepositoryImpl { // must have the exact 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;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
// You just autowire the the MyEntityRepository as usual
// (the Impl class is just impl detail, the clients don't even know about it)
@Service
public class SomeService {
@Autowired
private MyEntityRepository myEntityRepository;
public void someMethod(String x, long y) {
// call any method as usual
myEntityRepository.findByCommentEndsWith(x);
myEntityRepository.doSomeHql(y);
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样,除了您已经拥有的 Spring Data repo 之外,不需要任何接口。
我发现的唯一可能的缺点是:
Impl
类中的自定义方法被编译器标记为未使用,因此@SuppressWarnings("unused")
建议。Impl
班级的限制。(而在常规片段接口实现中,文档建议您可以有很多。)Impl
类放在不同的包中并且您的测试仅使用@DataJpaTest
,则必须添加@ComponentScan("package.of.the.impl.clazz")
到您的测试中,以便 Spring 加载它。Tom*_*zyk 10
这在使用上受到限制,但对于简单的自定义方法,您可以使用默认接口方法,如:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
在这个春季教程中写道:
Spring Data JPA还允许您通过简单地声明其方法签名来定义其他查询方法.
所以甚至可以声明方法如下:
Customer findByHobby(Hobby personHobby);
Run Code Online (Sandbox Code Playgroud)
如果object Hobby
是Customer的属性,那么Spring将自动为您定义方法.
Dan*_*tov 10
可接受的答案有效,但是存在三个问题:
AccountRepositoryImpl
。该文件明确指出,它已被称为AccountRepositoryCustomImpl
,自定义接口名加Impl
@Autowired
,这被认为是不良做法我找到了一种使之完美的方法,尽管并非没有使用另一个未公开的Spring Data功能:
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
}
}
Run Code Online (Sandbox Code Playgroud)
我使用以下代码从我的自定义实现访问生成的查找方法.通过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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
考虑到您的代码片段,请注意您只能将 Native 对象传递给 findBy### 方法,假设您要加载属于某些客户的帐户列表,一种解决方案是执行此操作,
@Query("Select a from Account a where a."#nameoffield"=?1")
List<Account> findByCustomer(String "#nameoffield");
Run Code Online (Sandbox Code Playgroud)
要求查询的表名与Entity类相同。对于进一步的实现,请看 这个
我喜欢 Danila 的解决方案并开始使用它,但团队中没有其他人喜欢为每个存储库创建 4 个类。Danila 的解决方案是这里唯一一个允许您在 Impl 类中使用 Spring Data 方法的解决方案。然而,我找到了一种只用一个类就能做到这一点的方法:
public interface UserRepository extends MongoAccess, PagingAndSortingRepository<User> {
List<User> getByUsername(String username);
default List<User> getByUsernameCustom(String username) {
// Can call Spring Data methods!
findAll();
// Can write your own!
MongoOperations operations = getMongoOperations();
return operations.find(new Query(Criteria.where("username").is(username)), User.class);
}
}
Run Code Online (Sandbox Code Playgroud)
您只需要某种方式来访问您的数据库 bean(在本例中为 MongoOperations)。MongoAccess 通过直接检索 bean 提供对所有存储库的访问:
public interface MongoAccess {
default MongoOperations getMongoOperations() {
return BeanAccessor.getSingleton(MongoOperations.class);
}
}
Run Code Online (Sandbox Code Playgroud)
其中 BeanAccessor 是:
@Component
public class BeanAccessor implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getSingleton(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getSingleton(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanAccessor.applicationContext = applicationContext;
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,你不能在界面中@Autowire。您可以将 bean 自动装配到 MongoAccessImpl 中,并在接口中提供一个方法来访问它,但 Spring Data 会崩溃。我认为它不希望看到与 PagingAndSortingRepository 间接关联的 Impl。
归档时间: |
|
查看次数: |
145591 次 |
最近记录: |