Использование Spring @Procedure для вызова StoredProcedure без привязки к таблице

Я хотел бы знать, можно ли вызвать хранимую процедуру без привязки ее к таблице/модели?

В моем случае у меня есть хранимая процедура в базе данных, которая отправляет почту. Я хотел бы вызвать это из Spring:

public interface SendEmail extends org.springframework.data.repository.Repository<Email, Long> {
    @Procedure(procedureName = "send_email")
    void sendEmail(String sender, String recipient, String ccRecipient, String subject, String message);
}

Приведенный выше код отлично компилируется и работает без проблем. Единственная проблема в том, что я хотел бы избавиться от extends Repository<Email, Long> - как мне это сделать? Если я просто удалю <Email, Long> (поскольку StoredProcedure ничего не возвращает и, следовательно, тип не нужен):

public interface SendEmail extends org.springframework.data.repository.Repository {
    @Procedure(procedureName = "send_email")
    void sendEmail(String sender, String recipient, String ccRecipient, String subject, String message);
}

Затем я получаю следующую ошибку:

Caused by: java.lang.IllegalArgumentException: Could not resolve id type of interface x.x.x.x.SendEmail!
    at org.springframework.data.repository.core.support.DefaultRepositoryMetadata.resolveIdType(DefaultRepositoryMetadata.java:81) ~[spring-data-commons-1.13.8.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.DefaultRepositoryMetadata.<init>(DefaultRepositoryMetadata.java:52) ~[spring-data-commons-1.13.8.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.AbstractRepositoryMetadata.getMetadata(AbstractRepositoryMetadata.java:71) ~[spring-data-commons-1.13.8.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryMetadata(RepositoryFactorySupport.java:233) ~[spring-data-commons-1.13.8.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:260) ~[spring-data-commons-1.13.8.RELEASE.jar:na]
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:101) ~[spring-data-jpa-1.11.8.RELEASE.jar:na]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    ... 41 common frames omitted

Если я удалю extends Repository<Email, Long> и у меня будет:

public interface SendEmail {
    @Procedure(procedureName = "send_email")
    void sendEmail(String sender, String recipient, String ccRecipient, String subject, String message);
}

то я получаю следующую ошибку:

Description:

Field sendEmail in x.x.x.EmailService required a bean of type 'x.x.x.SendEmail' that could not be found.


Action:

Consider defining a bean of type 'x.x.x.SendEmail' in your configuration.

В заключение мне нужно иметь модель с именем Email, которая сопоставлена ​​с таблицей в базе данных, чтобы вышеизложенное работало. Почему это так?

(Я пытался аннотировать интерфейс с помощью @Repositories и @Component)


person Henrik Helmø Larsen    schedule 30.01.2018    source источник


Ответы (2)


Repositories основаны на концепции репозитория, управляемого доменом: объект, который ведет себя аналогично набору совокупных корней, но с содержимым, хранящимся в некотором постоянном хранилище. Поэтому Repository необходимо знать совокупный корень, за который он отвечает, а также его тип идентификатора, чтобы найти его в хранилище.

Для репозиториев JPA это означает, что совокупность должна быть сущностью, отображаемой JPA. Безусловно, можно было бы реализовать репозитории на основе сущностей POJO и поддерживаемых хранимыми процедурами. В этой идее нет ничего плохого, за исключением того, что это не распространенный вариант использования, и для вашего варианта использования, вероятно, это излишне.

Если вы просто хотите вызвать хранимую процедуру, вам, вероятно, лучше использовать простой bean-компонент Spring и JdbcTemplate.

person Jens Schauder    schedule 31.01.2018
comment
Спасибо за ваш ответ. Я сделал решение, в котором я @Autowire EntityManager, а затем генерирую объект StoredProcedure: StoredProcedureQuery storeProcedure = entityManager.createStoredProcedureQuery(send_email); Это также отлично работает... - person Henrik Helmø Larsen; 31.01.2018
comment
Я знаю, что уже поздно, но можете ли вы поделиться, как вы это сделали, на github, это поможет или материалы? - person Remy; 08.09.2020
comment
Да... некоторый код для этого ответа был бы полезен. Как бы то ни было, это в лучшем случае косвенно полезно. - person TheJeff; 27.10.2020
comment
@HenrikHelmøLarsen, но где вы изначально объявили @NamedStoredProcedureQuery, которому вы дали имя "send_email“@NamedStoredProcedureQuery(name = "send_email", procedureName = "originial_name_in_sql"), должно было быть объявлено в сущности. - person toinetoine; 29.07.2021

Вы можете использовать таким образом:

@Repository
public class RepositoryClass implements DataRepository {
    @PersistenceContext
    private EntityManager em;
}
person Abid Khan    schedule 20.04.2021