Как получить доступ к Spring Data сконфигурированный менеджер объектов (factory) в пользовательской реализации

Я пишу специальную реализацию для репозитория данных JPA Spring. Поэтому у меня есть:

  • MyEntityRepositoryCustom = > интерфейс с настраиваемыми методами
  • MyEntityRepositoryUmpl = > реализация указанного интерфейса
  • MyEntityRepository = > стандартный интерфейс, который расширяет JpaRepository и MyEntityRepositoryCustom

Моя проблема заключается в следующем: в реализации MyEntityRepositoryUmpl мне нужно получить доступ к диспетчеру сущности, который был введен в Spring Data. Как его получить? Я могу использовать @PersistenceContext, чтобы получить его автоматически, но проблема заключается в том, что этот репозиторий должен работать в приложении, которое устанавливает несколько единиц устойчивости. Итак, чтобы сообщить Spring, какой мне нужен, мне пришлось бы использовать @PersistenceContext(unitName="myUnit"). Тем не менее, поскольку мои репозитории определены в многоразовом слое службы, я не могу знать, в какой точке будет имя единицы сохранения, которое будет настраиваться уровнем приложения более высокого уровня для ввода в мои репозитории.

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

Честно говоря, тот факт, что классы Impl полностью не знают о Spring Data, хотя описывается как сила в руководстве по Spring Data, на самом деле является сложностью, когда вам нужно получить доступ к тому, что обычно предоставляется Spring Данные сами в вашей пользовательской реализации (почти всегда, я бы сказал...).

Ответ 1

Лучшее, что я могу найти, - это создать "соглашение": мои репозитории заявляют, что они ожидают, что единица сохранения с именем myConventionalPU станет доступной. Затем прикладной уровень присваивает этому псевдониму менеджеру сущностей factory, который он устанавливает и вводит в Spring Data, поэтому мои пользовательские реализации могут получать правильную EMF с автосогласованием с использованием этого псевдонима. Здесь выдержка из моего контекста приложения:

<bean id="myEntityManagerFactory" name="myConventionalPU" 
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  [...]
</bean>

<jpa:repositories base-package="com.example"
  entity-manager-factory-ref="myEntityManagerFactory"
  transaction-manager-ref="transactionManager" />

И в моей пользовательской реализации:

@PersistenceContext(unitName = "myConventionalPU")
private EntityManager em;

Я открыл DATAJPA-669 с этим требованием.

Ответ 2

Начиная с версии Spring Data JPA 1.9.2 вы имеете доступ к EntityManager через JpaContext, см. http://docs.spring.io/spring-data/jpa/docs/1.9.2.RELEASE/reference/html/#jpa.misc.jpa-context. Пример:

@Component
public class RepositoryUtil
{
    @Autowired
    private JpaContext jpaContext;

    public void deatach(T entity)
    {
        jpaContext.getEntityManagerByManagedType(entity.getClass()).detach(entity);
    }
}

P.S. Этот подход не будет работать, если у вас есть несколько кандидатов EntityManager для некоторого класса, см. Реализацию JpaContext # getEntityManagerByManagedType → DefaultJpaContext # getEntityManagerByManagedType.

Ответ 3

Spring Данные JPA использует классы автоматической конфигурации для автоматического создания entityManagerFactory, dataSource и transactionManager.

Если вы хотите получить доступ к entityManager и управлять инстанцированием и настройками, вам необходимо определить свою собственную PersistenceConfiguration. Ниже приведен пример кода с помощью Java Config

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = { "com.test.repositories.*" })
    public class PersistenceJpaConfig {

        @Autowired
        JpaVendorAdapter jpaVendorAdapter;

        @Bean
        public DataSource dataSource() {
            return new EmbeddedDatabaseBuilder()
                    .setName("testdb")
                    .setType(EmbeddedDatabaseType.HSQL)
                    .build();
        }

        @Bean
        public EntityManager entityManager() {
            return entityManagerFactory().createEntityManager();
        }

        @Bean
        public EntityManagerFactory entityManagerFactory() {
            LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
            lef.setDataSource(dataSource());
            lef.setJpaVendorAdapter(jpaVendorAdapter);
            lef.setPackagesToScan("com.test.domain.*");
            lef.afterPropertiesSet();
            return lef.getObject();
        }

        @Bean
        public PlatformTransactionManager transactionManager() {
            return new JpaTransactionManager(entityManagerFactory());
        }
    }

Если у вас несколько источников данных, следуйте этой статье.