简体   繁体   中英

Spring dynamic JPA repository type

I have about 30 tables that I need to fill from an XML file. And I want to use JPA for that purpose.

Now I have 30 classes annotated with @Entity , config that scans entities and repositories;

Also I have:

@Repository
public interface MyRepository extends JpaRepository<MyEntity1, Long> {
}

And (some controller):

@Autowired
public MyRepository myRepository;
...
...
MyEntity1 entity = new MyEntity(...);
myRepository.save(entity);

It works fine with one @Entity but should I define 30 repositories for that?

I thought I could do something like this:

@Repository
public interface MyRepository<T> extends JpaRepository<T, Long> {
}

and then:

@Autowired
public MyRepository<MyEntity1> myRepository1;
@Autowired
public MyRepository<MyEntity2> myRepository2;

but that gave an error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepository1': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class java.lang.Object

Unfortunately you can't do this and you will have to write 30 separate repositories. You can however write generic repositories when the entities share a single table inheritance. (See the answer to Using generics in Spring Data JPA repositories )

What your code is trying to do is make a repository where the shared inheritance is on the class Object which isn't an @Entity hence the exception.

Also an additional minor note, you don't need to annotate your repositories with @Repository. Spring data automatically registers these as beans if it is configured correctly.

Try this approach:

Base class for all entities :

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;
}

Entities :

@Entity
public class Entity1 extends BaseEntity {

    private String name;
}

@Entity
public class Entity2 extends BaseEntity {

    private String name;
}

A common repo :

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

Usage :

public class BaseEntityRepoTest extends BaseTest {

    @Autowired
    private BaseEntityRepo repo;

    @Test
    public void baseEntityTest() throws Exception {

        BaseEntity entity1 = new Entity1("entity1");
        BaseEntity entity2 = new Entity2("entity2");

        repo.save(entity1);
        repo.save(entity2);

        List<BaseEntity> entities = repo.findAll();
        assertThat(entities).hasSize(2);

        entities.forEach(System.out::println);
    }
}

As far as I am aware what you are trying is not possible. Spring Data JPA needs an interface per Entity type for its repositories, Because Spring Data JPA will be creating the query implementations .

So it is advised that you have a Repository per Entity as it will allow you to add complex findByXXX methods in the future also.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM