У меня есть несколько сущностей, и я использую репозитории Spring Data JPA с спецификации запросить мою базу данных. Поэтому я создал общий класс SpecBuilder для построения моих запросов на основе описания запроса (MyQueryDescriptor).

public class Specs {
  public static <T extends MyEntityIFace> Specification<T> myfind(final MyQueryDescriptor qDesc) {
    return new Specification<T>() {
      @Override
      public Predicate toPredicate(Root<T> root, 
               CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        try {
          return SpecBuilder.mySpec(root, criteriaQuery, criteriaBuilder, qDesc);
        } catch (Exception e) {
          ...handle error...
        }
      }
    };
  }
}

Мои репозитории:

public interface Entity1DAO extends Repository<Entity1,Long>, 
                                    JpaSpecificationExecutor {
}

А также

public interface Entity2DAO extends Repository<Entity2,Long>, 
                                    JpaSpecificationExecutor {
}

Я не совсем уверен в трех вещах:
1)
Является ли использование универсального SpecBuilder чистым дизайном?

2)
Есть ли способ избежать написания этих интерфейсов репозитория для каждой сущности? Скажем, общий репозиторий?

3)
Класс MyQueryDescriptor имеет метод для возврата экземпляра Entity, который будет запрошен.
Каким будет чистый способ получить соответствующий репозиторий на основе класса сущности, избегая случая переключения? Я думал о том, чтобы добавить аннотацию с конкретным классом репозитория к каждой сущности, но это немного неприятно.
Должен ли я создать фабрику и внедрить карту вроде

Entity1.class => Entity1DAO
Entity2.class => Entity2DAO

?

6
Tobi 1 Окт 2015 в 09:09
1
«Проблема», которую я вижу, заключается в том, что отдельные объекты, вероятно, недостаточно похожи для общего репо. Думаю, вы можете получить базовые; например findAll(), save(T) и т. д., но почему бы не оставить детали на усмотрение? Вы можете позволить системе генерировать приятные вещи, например findThisByThatAndTheOther(T that, T2 theOther);?
 – 
ChiefTwoPencils
1 Окт 2015 в 09:50
Я знаю, что одно репо будет стоить мне гибкости в использовании вывода для методов поиска, таких как findThisByThatAndTheOther(T that, T2 theOther), но мой класс SpecBuilder должен иметь возможность создавать все запросы критериев, которые мне нужны. Поэтому создание пустых репозиториев для многих сущностей вызывает много накладных расходов.
 – 
Tobi
1 Окт 2015 в 10:03

2 ответа

Лучший ответ

Вы можете использовать наследование сущностей и использовать Spring Expression Language (SpEL), чтобы делать вызовы репозитория для нужных сущностей. Как и в моем последнем обновлении, здесь

2
Community 23 Май 2017 в 15:08
Как именно это помогает с JpaSpecificationExecutor?
 – 
crizzis
19 Апр 2021 в 19:22

Является ли использование универсального SpecBuilder чистым дизайном?

Зависит от того, какие критерии у вас есть для чистого дизайна. Будет ли один и тот же MyQueryDescriptor работать для разных сущностей? Конечно, у них разные свойства, поэтому вам нужно спросить себя, может ли данный MyQueryDescriptor быть ошибочно использован для несовместимого объекта и способы, которыми вы могли бы предотвратить это. Мы не можем это комментировать, поскольку не знаем, как работает ваш SpecBuilder.

Есть ли способ избежать написания этих интерфейсов репозитория для каждой сущности? Скажем, общий репозиторий?

Неа. Впрочем, это не так уж и много шаблонов.

  1. У класса MyQueryDescriptor есть метод для возврата экземпляра Сущность, которая будет опрошена. Каким чистым способом получить соответствующий репозиторий на основе класса сущности, избегая переключения случай?

Я полагаю, вы могли бы использовать getBeanProvider во время выполнения, где вы должны определить resolvableType как CrudRepository<MyEntityType, IdType>.

Однако на вашем месте я бы подумал о переходе на использование API критериев JPA без абстракции JpaSpecificationExecutor поверх него. Это, наверное, было бы более естественным. Дизайн репозиториев Spring основан на идее организации репозитория запросов вокруг данной конкретной сущности, тогда как ваш вариант использования, похоже, идет в прямо противоположном направлении - динамически выбирать сущность, а затем находить репозиторий, который подходит, просто для того, чтобы удовлетворить ограничения Spring. Похоже, вы боретесь с фреймворком в этом отношении.

0
crizzis 19 Апр 2021 в 19:38