Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data : how to use repository's inner interfaces outside the outer class?

When I have lot of repositories interface I usually use a wrapper like this :

@Component
public class RepositoryContainer(){

 @Autowired
 public Myrepo1 repo1;

 @Autowired
 public Myrepo2 repo2;
 //and so on....
}

Then I use it :

@Service
public class Myservice(){

 @Autowired
 RepositoryContainer repos;

 public void service1(){
   repos.repo1.findBy...
 }

}

The problem is this way of doing generates many files, since each repository is an interface, so I have same files for repositories as for entities.

To reduce the number of files I tried using nested interfaces :

@Repository
public class RepositoryContainer(){

  public interface Myrepo1 extends JpaRepository<Entity1, Long> {
  }

  public interface Myrepo2 extends JpaRepository<Entity2, Long> {
  }
  //and so on...
}

Now I am struggle because I can't access my repositories outside the class. Is there a way to do this :

@Service
public class Myservice(){

@Autowired
RepositoryContainer repos;

  public void service1(){
  //I would like to do this :
   repos.Myrepo1.findBy...
  }

}

Note that I've already enabled nested discovery repositories in

@EnableJpaRepositories( considerNestedRepositories = true )

Thanks a lot

like image 334
akuma8 Avatar asked Dec 18 '22 04:12

akuma8


2 Answers

Just turn on parameter considerNestedRepositories in EnableJpaRepositories annotation:

@SpringBootApplication
@EnableJpaRepositories(considerNestedRepositories = true)
public class Application {
    //...
}

And then you will be able to inject your 'inner' repo:

@Service
public class Myservice(){

    @Autowired Myrepo1 myrepo1;
    @Autowired Myrepo2 myrepo2;

      public void service1() {
          myrepo1.findBy...
          myrepo2.findBy...
      }
}

I think that there isn't another variant...

UPDATE

If the goal is to have a kind of 'clean code' I can propose a kind of approach:

public interface MyRepo1 extends JpaRepository<Entity1, Long> {
}

public interface MyRepo2 extends JpaRepository<Entity2, Long> {
}

@Getter
@RequiredArgsConstructor
@Component
public class RepoContainer {

    private final MyRepo1 myRepo1;
    private final MyRepo2 myRepo2;  
}

@RequiredArgsConstructor
@Service
public class MyService() {

    private final RepoContainer repoContainer;

    public void method() {
        repoContainer.getMyRepo1().findBy(...);
        repoContainer.getMyRepo2().findBy(...);
    }
}
like image 149
Cepr0 Avatar answered Jan 25 '23 23:01

Cepr0


After discussion with @Cepro0 here my solution :

@Repository
public class RepositoryContainer(){

  public interface Myrepo1 extends JpaRepository<Entity1, Long> {
  }

  public interface Myrepo2 extends JpaRepository<Entity2, Long> {
  }
   //I am using an inner bean to get my repositories
  @Component
  public class Container{
    @Autowired
    public Myrepo1 repo1;
    @Autowired 
    public Myrepo2 repo2; 
  }
}

Then :

@Service
public class Myservice(){

  @Autowired
  RepositoryContainer.Container repos;

  public void service1(){
   repos.repo1.findBy...
  }
}

This works perfectly and since today this is how I will proceed for reducing the number of file for each repository's interface and having a clean code because sometimes we need many repositories in a service and we have to inject them one-by-one.

If someone sees some drawbacks, please let me know.

like image 38
akuma8 Avatar answered Jan 25 '23 22:01

akuma8