0

I can create a repository via defining an interface on the appropriate JPA class A like the following:

public interface ARepository extends CrudRepository<A, Long>
{
}

and I can use that in my Controller (for example) via

@Autowired
private ARepository aRepository;

and just can do things like this:

aRepository.save(..);
aRepository.findAll();
..

No problem so far.

But my problem is that I have ca. 500 JPA classes and need to access each table which means to define 500 Repositories in the style of above.

So does exist an thing to create that either dynamically via some Spring Data "magic" which from my point of view should exist otherwise the above would not be possible. It looks like this is similar to my problem.

Apart from that one more issue related to the above. I can define findBy... methods in the interface and in the background there will be generated a query method for this particular attribute. The question is also if this can be done in a dynamic way related to the previous question, cause I have groups of tables which need supplemental query methods..

khmarbaise
  • 92,914
  • 28
  • 189
  • 235

2 Answers2

1

There is spring-data-generator which can automatically generate the interfaces for you.

Regarding your 2nd question I don't think you that can be done in a dynamic way. Java is statically compiled and there's no way to add members dynamically. There could be a tool that generates code for those methods but if that tool generates methods for all combinations of columns you will end up with a huge amount of methods.

Stephan
  • 922
  • 6
  • 14
  • First thanks for your answer but to generate the repositories could easily be done within 10-15 minutes..Maybe I wasn't clear enough I don't want to generate the code I would write by hand. I had something more generic in mind... – khmarbaise Mar 02 '18 at 14:25
1

You can make a base abstract entity for your 500 classes an then create one repo for this class. (I think it's a common practice to have a BaseEntity class with id, version etc. for every entity in the project).

For simple repo methods (like save, findAll etc.) it will work right from the box (note - entities must have the equal id type). For example:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstarct class BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
}

@Entity
public class Entity1 extends BaseEntity {
    private String name;
}

@Entity
public class Entity2 extends BaseEntity {
    private String name;
}

public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
}

Note that BaseEntity must have @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) to prevent of using singe table base_entity for every entity. And their ids must not intersect (see @GeneratedValue(strategy = GenerationType.SEQUENCE)).

Usage:

@RunWith(SpringRunner.class)
@SpringBootTest    
public class BaseEntityRepoTest {

    @Autowired private BaseEntityRepo repo;

    @Before
    public void setUp() throws Exception {    
        repo.save(asList(
                new Entity1("entity1"),
                new Entity2("entity2")
        ));
    }

    @Test
    public void readingTest() throws Exception {
        List<BaseEntity> entities = repo.findAll();
        assertThat(entities).hasSize(2);
    }
}

Related to your second question you can use this approach:

public interface BaseEntityRepo extends JpaRepository<BaseEntity, Long> {
    <T> T findById(Long id, Class<T> type);
}

Usage:

@Test
public void findById() {
    final Entity1 entity1 = repo.findById(1L, Entity1.class);
    final Entity2 entity2 = repo.findById(2L, Entity2.class);
    assertThat(entity1).isNotNull();
    assertThat(entity2).isNotNull();
}

But you can build repo query methods only for 'common' properties of inherited entities which are present in the base class. To make this method work you must move the name parameter to the BaseEntity:

<T> List<T> findAllByNameLike(String name, Class<T> type);
Cepr0
  • 28,144
  • 8
  • 75
  • 101