web-dev-qa-db-fra.com

Comment accéder au gestionnaire d'entités configuré par Spring Data (usine) dans une implémentation personnalisée

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ées
  • MyEntityRepositoryUmpl => implémentation de l'interface ci-dessus
  • MyEntityRepository => 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 ...).

13
Mauro Molinari

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.

4
Mauro Molinari

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.

22
Alexander du Sautoy

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.

3
Nitin Arora