3

I have a set of entity classes and repository definitions and N databases, all of which have the schema. How can I instantiate N repositories pointing to each of the N databases.

@Entity
public class Student {
}

public interface StudentRepository extends JpaRepository< Student, Long> {
}

Making as many copies of repository interfaces as the number of databases (http://www.baeldung.com/spring-data-jpa-multiple-databases) and using dynamic datasource routing (http://spring.io/blog/2007/01/23/dynamic-datasource-routing/) were two solutions I found.

But, what I need is something like

@Component
public class Foo {

    @Autowired
    StudentRepository studentRepositoryForDatabase1;
    @Autowired
    StudentRepository studentRepositoryForDatabase2;

}

Is this feasible?

Ranjith
  • 1,623
  • 3
  • 21
  • 34
  • not a duplicate, but might be relevant - http://stackoverflow.com/questions/12612288/spring-data-jpa-with-multiple-datasources-but-only-one-set-of-repositories. basically use a single repo and switch datasources (might not be what you want though) – radai Apr 28 '16 at 14:14

1 Answers1

1

How large is N? If classes should not be created N times, you'd probably have to instantiate SimpleJpaRepository(Class<T> domainClass, EntityManager em) yourself (which otherwise is the interface used for). There you can pass the EntityManager of your desired database.

Pseudo code, but it should in general work like this:

//maybe spring is capable of injecting all ems here?
@Autowired
private List<EntityManager> ems;

@Autowired
private ApplicationContext ctx;

@Autowired
private ConfigurableBeanFactory bf;

int n = 10;
for (int i = 0; i < n; i++) {
    //you'd probably need a way to identify which "em" maps to which number
    CrudRepository dao = new YourBeanRepository(YourBean.class, emN);
    bf.registerSingleton("YourBean" + n, dao);
}

ctx.getBean("YourBean1");

One sidequestion: why do you have multiple databases with the same schema? Maybe your application or database design is not correct here, if you might want to give futher details.

Update: you might try something like this:

public class YourBeanRepository<T> extends SimpleJpaRepository<T> {
    //repo containing your findFirstBy()...
    @Autowired
    private StudentRepository dao; //provide a getter

    public YourBeanRepository(Class<T> clazz, EntityManager em) {
        super(clazz, em);
    }
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • Autowire for @Autowired StudentRepository studentRepositoryForDatabase1; is failing as the created repository is of type SimpleJpaRepository and not StudentRepository. Also, if this method of creating repositories is followed, does it mean that the repository cannot contain methods like findByFirstName(String) etc (whose implementation is provided by Spring data) ? – Ranjith Apr 28 '16 at 15:02
  • Of course you have then to wire `@Autowired @Qualifier("YourBean1")`, as spring otherwise has no chance to detect the desired method. Or just inject the `ApplicationContext` and use `ctx.getBean("YourBean1");` for selecting the desired bean, which is probably way better than creating `N` @Autowired member variables of the StudentRepository. Regarding your 2nd question, see my update. – membersound Apr 28 '16 at 15:05
  • I added the qualifier annotation but it isn't working `@Qualifier("studentRepository1") @Autowired StudentRepositorystudentRepository1;` The error I am getting is `Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [kb.repo.StudentRepository ] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=studentRepository1), @org.springframework.beans.factory.annotation.Autowired(required=true)}` – Ranjith Apr 28 '16 at 15:10
  • As written: if you don't want to create `N` classes of the StudentRepository, then you shouldn't either create `N` autowired variables. You cannot save boilerplate on the class files side, and then add boilerplate on the code side. I would use the `ctx.getBean()` inside your serviceclasses, without autowiring the `N`. – membersound Apr 28 '16 at 15:11
  • Another update: you could try adding the `interface StudentRepository` into the `YourBeanRepository`. Maybe you have to do this using a `setter` after `new YourBeanRepository()` creation. Then provide a `getter` to that injected inferface to access your `findByX()`methods. – membersound Apr 28 '16 at 15:23