36

是否可以使用 Spring Data 创建只读存储库?

我有一些实体链接到视图和一些子实体,我想为它们提供一个带有一些方法的存储库,比如findAll()findOne()以及一些带有@Query注释的方法。我想避免提供像save(…)and这样的方法,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
}

谢谢!

4

6 回答 6

66

是的,要走的路是添加一个手工制作的基础存储库。你通常使用这样的东西:

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);
}

定义基本 repo 的关键部分是方法声明带有与声明的方法相同的签名CrudRepository如果在这种情况下我们仍然可以将调用路由到支持存储库代理的实现 bean。我在 SpringSource 博客中写了一篇关于该主题的更详细的博客文章。

于 2012-06-20T13:04:11.790 回答
35

为了扩展 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();

}
于 2016-05-18T10:54:29.390 回答
7

正如我们在文档中看到的,这可以通过实现org.springframework.data.repository.Repository来实现。

于 2012-06-19T18:42:14.517 回答
5

这是只读的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(不允许的方法)。

于 2020-05-15T17:41:58.627 回答
4

对我来说,以下工作。使用 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();
}
于 2018-05-15T10:19:54.893 回答
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.");
    }
}

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

于 2020-07-01T11:49:02.897 回答