Базовый репозиторий Spring JPA

Я создал собственный репозиторий для переопределения методов сохранения и попытался подключить его, как описано в файле весенние документы. Я не получаю ошибок, все объекты и репозитории обнаруживаются при запуске, и когда я вызываю repo.saveAll(entities), постоянство работает нормально. Однако мой пользовательский код никогда не вызывается. Я добавил операторы журнала и даже бросил RuntimeExceptions в свой код, просто чтобы увидеть, выполняется ли он, но он определенно игнорируется. Какой шаг я пропустил?

@Configuration
@Profile("test")
@EnableJpaRepositories(repositoryBaseClass = SetClientInfoRepositoryImpl.class,
        basePackages = {"gov.penndot.hwy.apras.common.repository" }, 
        entityManagerFactoryRef = "serviceEntityManagerFactory", 
        transactionManagerRef = "serviceTransactionManager")
public class TestDatabaseConfig {

    @Bean(name = "serviceDataSource")
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
        dataSource.setUsername("sa");
        dataSource.setPassword("sa");

        return dataSource;
    }

    @Bean
    public EntityManagerFactoryBuilder entityManagerFactoryBuilder() {
        return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), new HashMap<String, Object>(), null);
    }

    @Bean(name = "serviceEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean serviceEntityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("serviceDataSource") DataSource dataSource) {

        return builder
                .dataSource(dataSource)
                .packages("stuff")
                .persistenceUnit("service")
                .build();
    }

    @Bean(name = "serviceTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("serviceEntityManagerFactory") EntityManagerFactory serviceEntityManagerFactory) {
        return new JpaTransactionManager(serviceEntityManagerFactory);
    }

Репозиторий:

@NoRepositoryBean
    public class SetClientInfoRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
        private static final Logger log = LoggerFactory.getLogger(SetClientInfoRepositoryImpl.class);
        private final EntityManager em;

        public SetClientInfoRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
            super(entityInformation, entityManager);
            this.em = entityManager;
        }

        @Transactional
        @Override
        public <S extends T> S save(S entity) {
            setClientInfo();
            return super.save(entity);
        }

        @Transactional
        @Override
        public void deleteById(ID id) {
            setClientInfo();
            super.deleteById(id);
        }

        @Transactional
        @Override
        public void delete(T entity) {
            setClientInfo();
            super.delete(entity);
        }

        @Transactional
        @Override
        public void deleteAll(Iterable<? extends T> entities) {
            setClientInfo();
            super.deleteAll(entities);
        }

        @Transactional
        @Override
        public void deleteInBatch(Iterable<T> entities) {
            setClientInfo();
            super.deleteInBatch(entities);
        }

        @Transactional
        @Override
        public void deleteAll() {
            setClientInfo();
            super.deleteAll();
        }

        @Transactional
        @Override
        public void deleteAllInBatch() {
            setClientInfo();
            super.deleteAllInBatch();
        }

        @Transactional
        @Override
        public <S extends T> S saveAndFlush(S entity) {
            setClientInfo();
            return super.saveAndFlush(entity);
        }

        @Transactional
        @Override
        public <S extends T> List<S> saveAll(Iterable<S> entities) {
            setClientInfo();
            super.saveAll(entities);
            throw new RuntimeException("foo");
        }

        private void setClientInfo() {
            log.debug("Entering setClientInfo method");
            [stuff]
        }
    }

Чтобы подтвердить, вы вызываете метод saveAll() в SetClientInfoRepositoryImpl, а не в каком-то другом классе? Обычно здесь нужно создать интерфейс для SetClientInfoRepository, автоматически связать/внедрить этот репозиторий, куда вам нужно, а затем вызвать метод saveAll(), используя этот интерфейс. stackoverflow.com/questions/13036159/…

Derek 11.03.2019 18:46

Вы уверены, что ваш основной класс конфигурации, в котором вы используете @EnableJpaRepositories, помечен @Profile("!test")?

Selindek 11.03.2019 19:32

@Derek - (спасибо за ответ!) Я вызываю метод saveAll() в другом интерфейсе, аннотированном как репозиторий. Зачем мне нужен другой интерфейс, когда метод тот же, а документы Spring не вызывают его? Я использовал пользовательский интерфейс, когда требуются пользовательские методы

GeneO 11.03.2019 20:27

@Selindek - (спасибо за ответ!) Да, проблема не в профиле. Правильная конфигурация базы данных загружается в Spring, потому что все сохранение происходит в базе данных h2, как определено в классе конфигурации.

GeneO 11.03.2019 20:29

Хорошо, тогда давайте удостоверимся, что оригинал @EnableJpaRepositories не выбран: закомментируйте его и запустите тест таким образом.

Selindek 12.03.2019 17:52

@Selindek: закомментировано, но поведение такое же. Я отредактировал, чтобы включить полный класс конфигурации базы данных (у меня есть несколько БД в этой службе, поэтому требуется несколько конфигураций.) Может ли один из экземпляров в этом классе перезаписывать аннотированный репозиторийBaseClass? Когда я отлаживаю метод getTargetRepository в Spring, он определенно использует SimpleJpaRepository в качестве базового класса.

GeneO 12.03.2019 20:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
906
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, это довольно отчаянная идея, но попробовать стоит...

Создайте пользовательский интерфейс репозитория:

public interface SetClientInfoRepository<T, ID> extends JpaRepository<T, ID> {
}

Реализуйте этот интерфейс репозитория с помощью собственного базового репозитория:

public class SetClientInfoRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements SetClientInfoRepository<T, ID> {
}

... и, наконец, расширить этот интерфейс интерфейсами вашего репозитория вместо JpaRepository

Таким образом, Spring должен создает репозиторий-прокси из вашей реализации, потому что нет других классов, которые он мог бы использовать. Кроме того, если он не может создать репозитории по какой-либо причине, вы получите более информативное исключение во время запуска.

Использование пользовательского интерфейса репозитория само по себе неплохо, потому что всегда есть хороший шанс, что вы захотите добавить некоторые общие пользовательские методы в свои репозитории позже, и тогда это пригодится.

Спасибо за всю твою помощь! Ваш ответ сработал. Я создал новый простой проект и получил исходную аннотацию baseRepositoryClass, работающую правильно, поэтому я уверен, что где-то напортачил конфигурацию.

GeneO 13.03.2019 15:51

Я считаю, что Spring Data JPA (и Spring Data Rest) являются (одним из) наиболее сложными пакетами Spring. Я не удивлюсь, если эта проблема возникнет из-за ошибки в ней.

Selindek 13.03.2019 16:13

Другие вопросы по теме