Доступ к JPA-методам через наследование и параметризованный репозиторий - PullRequest
0 голосов
/ 05 марта 2020

Скажем, у меня есть абстрактная сущность

@MappedSuperclass
@Data
public abstract class AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(nullable = false, updatable = false)
    protected Integer id;
    @Column(nullable = false, unique = true)
    protected String name;

}

с неким абстрактным репозиторием

@NoRepositoryBean
public interface AbstractRepository<C extends AbstractEntity> extends JpaRepository<C, Integer> {}

, который должен служить одной зависимостью для нескольких сущностей. Сущности расширяют абстрактную сущность и, таким образом, AbstractRepository:

public interface RealEntityRepository extends AbstractRepository<RealEntity> {}

В моем сервисе я хочу использовать наследование jpa, чтобы избавиться от конструктора-разветвителя (он раздут из-за слишком большого количества realEntityRepos) и реализации методов для каждой сущности , Поэтому вместо x методов, подобных этому, для каждой сущности

void findRealEntity(RealEntity entity) {
    entity.setId(realEntityRepository.findOne(entity.getName())
            .map(RealEntity ::getId)
            .orElseThrow(() -> new SomeException(entity.getName())));
}

Я хочу иметь только один вызов метода, как в следующем псевдокоде (я знаю, что нельзя создавать экземпляры абстрактных классов), который принимает сущность в качестве абстрактной сущности для аргумент, вызывает дочернее репо и выполняет методы jpa в этом конкретном c дочернем репо.

void findEntity(AbstractEntity entity) {
entity.setId(abstractEntityRepository.findOne(entity.getName())
        .map(AbstractEntity::getId)
        .orElseThrow(() -> new SomeException(entity.getName())));

}

Это мой сервис на данный момент, он работает так, но он раздувается:

@Service
public class SomeService {

private final RealEntity1Repository realEntity1Repository;
private final RealEntity2Repository realEntity2Repository;
private final RealEntity3Repository realEntity3Repository ;
... 5 more times ..

public SomeService(RealEntity1Repository realEntity1Repository, RealEntity2Repository realEntity2Repository,
                            RealEntity3Repository realEntity3Repository,
 ... 5 more) {
    this.realEntity1Repository = realEntity1Repository;
    this.realEntity2Repository = realEntity2Repository;
    this.realEntity3Repository = realEntity3Repository;
    ... 5 more
}
... some methods

void findRealEntity1(RealEntity1 entity) {
entity.setId(realEntity1Repository.findOne(entity.getName())
        .map(RealEntity1::getId)
        .orElseThrow(() -> new SomeException(entity.getName())));
}

void findRealEntity2(RealEntity2 entity) {
entity.setId(realEntity2Repository.findOne(entity.getName())
        .map(RealEntity2::getId)
        .orElseThrow(() -> new SomeException(entity.getName())));
}
...

ОБНОВЛЕНИЕ

Спасибо подсказкам @Antoniosss. Я решил проблему!

Добавьте Optional<C> findByName(String name); в SuperRepository, а затем создайте новый сервис, который реализует репозиторий сущностей, определяющий c методы транзакций. Вызовите этот сервис в предыдущем сервисе при реализации отображения между AbstractEntity и методами, определяющими сущность c:

public void mapAbstractEntity(AbstractEntity abstractEntity) {
  if (abstractEntity instanceof RealEntity1 { // call RealEntity1 method from service}
  else if (abstractEntity instanceof RealEntity2) { ... }

1 Ответ

0 голосов
/ 18 марта 2020

На основе фактического кода - вы можете добавить findByName generi c метод к абстрактному репозиторию, создать карту, которая отображает тип объекта в репозиторий, и затем использовать единственную реализацию findRealEntity(AbstractEntity), которая выберет правильный репозиторий и вызовет findByName в теме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...