1
resposta

Join entre entidades de bancos diferentes com spring data jpa

Olá a todos, estou precisando de uma ajuda, no meu projeto eu tenho dois data sources configurados para duas bases de dados diferentes, e preciso implementar um cross join entre duas entidades que estão separadas por pacotes para cada data source, ou seja, eu tenho a entidade A no pacote A configurada para ser gerenciada via data source A, e tenho a entidade B no pacote B configurada para ser gerenciada pelo data source B, e preciso fazer algo parecido com isso:

select new com.example.basea.A(a,b) from A a, com,example.baseb.B b where a.id = b.id

Existe configurações para cada data source anotadas com @EnableTransactionManagement, @EnableJpaRepositories e beans usando @Primary e @Qualifier. O projeto roda tranquilo quando as rotinas são executadas entre as entidades do mesmo data source, mas preciso fazer um join entre as duas bases. Já estou travado nisso há pelo menos um dia, e preciso de ajuda dos senhores...

1 resposta

Olá Gilmar!

A situação que você descreveu é um pouco complexa, pois o JPA não suporta nativamente a junção de entidades que estão em diferentes EntityManager ou DataSource. Cada EntityManager é vinculado a um DataSource específico e não tem conhecimento de outros DataSource.

Uma possível solução para o seu problema é utilizar o recurso de múltiplos DataSources do Spring. Com essa abordagem, você pode configurar um EntityManagerFactory para cada DataSource e, em seguida, criar um EntityManager para cada um deles. Dessa forma, você poderá realizar consultas entre as entidades de bancos de dados diferentes.

Você precisa criar as classes de configuração para cada DataSource. Por exemplo, vamos supor que você tenha duas classes de configuração chamadas DataSourceAConfig e DataSourceBConfig. Em cada uma dessas classes, você deve configurar o EntityManagerFactory e o EntityManager correspondentes.

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "entityManagerFactoryA",
    transactionManagerRef = "transactionManagerA",
    basePackages = { "com.example.basea" }
)
public class DataSourceAConfig {

    @Primary
    @Bean(name = "dataSourceA")
    @ConfigurationProperties(prefix = "spring.datasourceA")
    public DataSource dataSourceA() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "entityManagerFactoryA")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryA(EntityManagerFactoryBuilder builder, @Qualifier("dataSourceA") DataSource dataSourceA) {
        return builder
            .dataSource(dataSourceA)
            .packages("com.example.basea")
            .build();
    }

    @Primary
    @Bean(name = "transactionManagerA")
    public PlatformTransactionManager transactionManagerA(@Qualifier("entityManagerFactoryA") EntityManagerFactory entityManagerFactoryA) {
        return new JpaTransactionManager(entityManagerFactoryA);
    }

    @Primary
    @Bean(name = "entityManagerA")
    public EntityManager entityManagerA(@Qualifier("entityManagerFactoryA") EntityManagerFactory entityManagerFactoryA) {
        return entityManagerFactoryA.createEntityManager();
    }
}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "entityManagerFactoryB",
    transactionManagerRef = "transactionManagerB",
    basePackages = { "com.example.baseb" }
)
public class DataSourceBConfig {

    @Bean(name = "dataSourceB")
    @ConfigurationProperties(prefix = "spring.datasourceB")
    public DataSource dataSourceB() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "entityManagerFactoryB")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryB(EntityManagerFactoryBuilder builder, @Qualifier("dataSourceB") DataSource dataSourceB) {
        return builder
            .dataSource(dataSourceB)
            .packages("com.example.baseb")
            .build();
    }

    @Bean(name = "transactionManagerB")
    public PlatformTransactionManager transactionManagerB(@Qualifier("entityManagerFactoryB") EntityManagerFactory entityManagerFactoryB) {
        return new JpaTransactionManager(entityManagerFactoryB);
    }

    @Bean(name = "entityManagerB")
    public EntityManager entityManagerB(@Qualifier("entityManagerFactoryB") EntityManagerFactory entityManagerFactoryB) {
        return entityManagerFactoryB.createEntityManager();
    }
}

Agora que você tem as configurações, você pode realizar o join entre as entidades de bancos de dados diferentes. Você pode injetar os EntityManagers correspondentes e utilizá-los para realizar a consulta desejada.

@Autowired
@Qualifier("entityManagerA")
private EntityManager entityManagerA;

@Autowired
@Qualifier("entityManagerB")
private EntityManager entityManagerB;

public void realizarJoin() {
    String query = "select new com.example.basea.A(a,b) from A a, com.example.baseb.B b where a.id = b.id";
    List<A> resultado = entityManagerA.createQuery(query, A.class).getResultList();
    // Faça o que for necessário com o resultado da consulta
}

Lembre-se de adaptar o exemplo de acordo com a estrutura do seu projeto e as configurações dos seus DataSources.

Espero que essa solução seja útil para você! Se tiver mais alguma dúvida, é só perguntar. Bons estudos!