使用Spring Data创建只读存储库

时间:2012-06-19 18:30:42

标签: java spring jpa spring-data spring-data-jpa

是否可以使用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
}

谢谢!

6 个答案:

答案 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.");
    }
}

希望我能帮助别人(ノ^∇^)