J'écris une implémentation personnalisée pour un référentiel Spring Data JPA. Donc j'ai:
MyEntityRepositoryCustom
=> interface avec les méthodes personnaliséesMyEntityRepositoryUmpl
=> implémentation de l'interface ci-dessusMyEntityRepository
=> interface standard qui étend JpaRepository
et MyEntityRepositoryCustom
Mon problème est le suivant: dans l'implémentation de MyEntityRepositoryUmpl
j'ai besoin d'accéder au gestionnaire d'entités qui a été injecté dans Spring Data. Comment l'obtenir? Je peux utiliser @PersistenceContext
Pour obtenir un câblage automatique, mais le problème est que ce référentiel doit fonctionner dans une application qui configure plusieurs unités de persistance. Donc, pour dire à Spring celui dont j'ai besoin, je devrais utiliser @PersistenceContext(unitName="myUnit")
. Cependant, comme mes référentiels sont définis dans une couche de service réutilisable, je ne peux pas savoir à ce stade quel sera le nom de l'unité de persistance que la couche d'application de niveau supérieur configurera pour être injectée dans mes référentiels.
En d'autres termes, ce que je devrais faire est d'accéder au gestionnaire d'entités que Spring Data lui-même utilise, mais après un examen (pas si rapide) de la documentation Spring Data JPA, je n'ai rien trouvé pour cela.
Honnêtement, le fait que les classes Impl
ignorent totalement Spring Data, bien que décrit comme une force dans le manuel Spring Data, est en fait une complication chaque fois que vous devez accéder à quelque chose qui est généralement fourni par Spring Data lui-même dans votre implémentation personnalisée (presque toujours, je dirais ...).
Le mieux que j'ai pu trouver est de mettre en place une "convention": mes référentiels déclarent s'attendre à ce qu'une unité de persistance nommée myConventionalPU
soit mise à disposition. La couche d'application affecte ensuite cet alias à la fabrique de gestionnaires d'entités qu'elle configure et injecte dans Spring Data, afin que mes implémentations personnalisées puissent recevoir le bon EMF avec câblage automatique en utilisant cet alias. Voici un extrait de mon contexte d'application:
<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" />
Et dans mon implémentation personnalisée:
@PersistenceContext(unitName = "myConventionalPU")
private EntityManager em;
J'ai ouvert DATAJPA-669 avec cette exigence.
Depuis la version Spring Data JPA 1.9.2, vous avez accès à EntityManager via JpaContext, voir: http://docs.spring.io/spring-data/jpa/docs/1.9.2.RELEASE/reference/html/ # jpa.misc.jpa-context . Exemple:
@Component
public class RepositoryUtil
{
@Autowired
private JpaContext jpaContext;
public void deatach(T entity)
{
jpaContext.getEntityManagerByManagedType(entity.getClass()).detach(entity);
}
}
P.S. Cette approche ne fonctionnera pas si vous avez plusieurs candidats EntityManager pour une classe, voir la mise en œuvre de JpaContext # getEntityManagerByManagedType -> DefaultJpaContext # getEntityManagerByManagedType.
Spring Data JPA utilise des classes de configuration automatique pour générer automatiquement entityManagerFactory, dataSource et transactionManager.
Si vous souhaitez accéder à entityManager et contrôler l'instanciation et les paramètres, vous devez définir votre propre PersistenceConfiguration. Voici un exemple de code utilisant 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());
}
}
Si vous avez plusieurs sources de données, suivez cet article.