Как получить доступ к 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());
}
}
Если у вас несколько источников данных, следуйте этой статье.