是否可以使用Spring Data创建只读存储库?
我有一些实体链接到视图和一些子实体,我想为其提供一些存储库,其中包含findAll()
,findOne()
等一些方法以及一些带有@Query
注释的方法。我想避免提供像save(…)
和delete(…)
这样的方法,因为它们毫无意义并且可能会产生错误。
public interface ContactRepository extends JpaRepository<ContactModel, Integer>, JpaSpecificationExecutor<ContactModel> {
List<ContactModel> findContactByAddress_CityModel_Id(Integer cityId);
List<ContactModel> findContactByAddress_CityModel_Region_Id(Integer regionId);
// ... methods using @Query
// no need to save/flush/delete
}
谢谢!
答案 0 :(得分:46)
是的,要走的路是添加一个手工制作的基础库。你通常使用这样的东西:
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
Iterable<T> findAll();
}
您现在可以拥有刚刚定义的具体的repos扩展:
public interface PersonRepository extends ReadOnlyRepository<Person, Long> {
T findByEmailAddress(String emailAddress);
}
定义基本仓库的关键部分是方法声明带有与CrudRepository
中声明的方法相同的签名,如果是这种情况我们仍然可以将调用路由到实现中bean支持存储库代理。我在SpringSource博客中写了一篇关于该主题的更详细的blog post。
答案 1 :(得分:22)
要扩展Oliver Gierke的答案,在更新版本的Spring Data中,您需要在ReadOnlyRepository(父接口)上使用@NoRepositoryBean注释来防止应用程序启动错误:
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
@NoRepositoryBean
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
List<T> findAll();
}
答案 2 :(得分:6)
据我们在文档中可以看到,这可以通过实施org.springframework.data.repository.Repository来实现。
答案 3 :(得分:4)
这是只读的PagingAndSortingRepository
package com.oracle.odc.data.catalog.service.core.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RestResource;
/**
* Extension of {@link PagingAndSortingRepository} but without modification capabilities
*
* @author XYZ
* @see Sort
* @see Pageable
* @see Page
*/
@NoRepositoryBean
public interface ReadOnlyPagingAndSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
@Override
@RestResource(exported=false)
<S extends T> S save(S entity);
@Override
@RestResource(exported=false)
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
@Override
@RestResource(exported=false)
void deleteById(ID id);
@Override
@RestResource(exported=false)
void delete(T entity);
@Override
@RestResource(exported=false)
void deleteAll(Iterable<? extends T> entities);
@Override
@RestResource(exported=false)
void deleteAll();
}
如果您尝试POST或DELETE,您将得到405(不允许使用方法)。
答案 4 :(得分:0)
对我来说,以下工作。使用Oliver的解决方案,我在启动时遇到错误Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property findOne found for type
。
@NoRepositoryBean
public interface ReadOnlyRepository<T,ID> extends Repository<T, ID> {
Optional<T> findById(ID var1);
boolean existsById(ID var1);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> var1);
long count();
}
答案 5 :(得分:0)
或者,如果您要自己实现或阻止此操作-您可以执行以下操作(适用于Java 8及更高版本):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.lang.NonNull;
import java.util.List;
@NoRepositoryBean
public interface ReadOnlyRepository<T, ID> extends JpaRepository<T, ID> {
@Override
@NonNull
default <S extends T> S save(@NonNull S entity) {
throw new RuntimeException("Action not allowed");
}
@Override
@NonNull
default <S extends T> List<S> saveAll(@NonNull Iterable<S> iterable) {
throw new RuntimeException("Action not allowed.");
}
@Override
@NonNull
default <S extends T> S saveAndFlush(@NonNull S s) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void delete(@NonNull T entity) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAll() {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAll(@NonNull Iterable<? extends T> entities) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAllInBatch() {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteById(@NonNull ID id) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteInBatch(@NonNull Iterable<T> iterable) {
throw new RuntimeException("Action not allowed.");
}
}
希望我能帮助别人(ノ^∇^)