How to access Spring Data configured entity manage

2019-01-31 15:03发布

I'm writing a custom implementation for a Spring Data JPA repository. So I have:

  • MyEntityRepositoryCustom => interface with the custom methods
  • MyEntityRepositoryUmpl => implementation of the above interface
  • MyEntityRepository => standard interface which extends JpaRepository and MyEntityRepositoryCustom

My problem is this: within the implementation of MyEntityRepositoryUmpl I need to access the entity manager that was injected into Spring Data. How to get it? I can use @PersistenceContext to get it autowired, but the problem is that this repository must work in an application that sets up more than one persistence units. So, to tell Spring which one I need, I would have to use @PersistenceContext(unitName="myUnit"). However, since my repositories are defined in a reusable service layer, I can't know at that point what will be the name of the persistence unit that the higher-level application layer will configure to be injected into my repositories.

In other words, what I would need to do is to access the entity manager that Spring Data itself is using, but after a (not so quick) look at Spring Data JPA documentation I couldn't find anything for this.

Honestly, the fact that the Impl classes are totally unaware of Spring Data, although described as a strength in Spring Data manual, is actually a complication whenever you need to access something that is usually provided by Spring Data itself in your custom implementation (almost always, I would say...).

3条回答
太酷不给撩
2楼-- · 2019-01-31 15:15

Spring Data JPA uses Auto configuration classes to auto generate entityManagerFactory, dataSource and transactionManager.

If you want get access to entityManager and control the instantiation and settings, you need to define your own PersistenceConfiguration. Below is the sample code using 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());
        }
    }

If you have multiple data sources, follow this article.

查看更多
叛逆
3楼-- · 2019-01-31 15:16

Since version Spring Data JPA 1.9.2 you have access to EntityManager through JpaContext, see: http://docs.spring.io/spring-data/jpa/docs/1.9.2.RELEASE/reference/html/#jpa.misc.jpa-context. Example:

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

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

P.S. This approach will not work if you have more than one EntityManager candidate for some Class, see implementation of JpaContext#getEntityManagerByManagedType -> DefaultJpaContext#getEntityManagerByManagedType.

查看更多
一纸荒年 Trace。
4楼-- · 2019-01-31 15:29

The best I could find is to set up a "convention": my repositories declare that they expect a persistence unit named myConventionalPU to be made available. The application layer then assigns that alias to the entity manager factory that it sets up and injects into Spring Data, so my custom implementations can receive the correct EMF with autowiring by using that alias. Here's an excerpt of my application context:

<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" />

And within my custom implementation:

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

I opened DATAJPA-669 with this requirement.

查看更多
登录 后发表回答