web-dev-qa-db-fra.com

Requêtes personnalisées avec CrudRepository

Je souhaite personnaliser mes requêtes avec CrudRepository:

Voici mon code:

@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {

@Query("UPDATE customer c SET c.firstName = :firstName WHERE c.id = :id")
Integer setNewFirstNameForId(@Param("firstName") String firstName, @Param("id") long id);   
}



@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
    private String firstName;
    private String lastName;

    protected Customer() {}

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }

Mais, quand je compile tout cela, j'ai ceci un extrait de l'erreur: "Erreur lors de la création du bean avec le nom 'customerRepository': L'invocation de la méthode init a échoué; ..."

Merci d'avance,

éditer :

Voici mon erreur:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': Invocation of init method failed; nested exception is Java.lang.IllegalArgumentException: Validation failed for query for method public abstract Java.lang.Integer hello.CustomerRepository.setNewFirstNameForId(Java.lang.String,long)!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.Java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.Java:681)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.Java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:482)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.Java:84)
at hello.Application.main(Application.Java:75)
Caused by: Java.lang.IllegalArgumentException: Validation failed for query for method public abstract Java.lang.Integer hello.CustomerRepository.setNewFirstNameForId(Java.lang.String,long)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.Java:80)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.Java:54)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.Java:65)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.Java:48)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:115)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:160)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:69)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.Java:304)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.Java:161)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.Java:220)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.Java:206)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.Java:84)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.Java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1549)
... 11 more
Caused by: Java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: customer is not mapped [UPDATE customer c SET c.firstName = :firstName WHERE c.id = :id]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.Java:1750)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.Java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.Java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.Java:331)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:606)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.Java:334)
at com.Sun.proxy.$Proxy38.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.Java:74)
... 24 more
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: customer is not mapped [UPDATE customer c SET c.firstName = :firstName WHERE c.id = :id]
at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException(QuerySyntaxException.Java:96)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.Java:120)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.Java:234)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.Java:158)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.Java:126)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.Java:88)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.Java:190)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.Java:301)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.Java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.Java:1796)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.Java:328)
... 31 more
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: customer is not mapped
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.Java:189)
at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.Java:109)
at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.Java:95)
at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.Java:331)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.Java:3554)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.Java:3443)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.Java:706)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.Java:363)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.Java:255)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.Java:278)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.Java:206)
... 39 more
11
user2931656

Votre premier problème est dans votre JPQL:

@Query("UPDATE customer c SET c.firstName = :firstName WHERE c.id = :id")

taper à

@Query("UPDATE Customer c SET c.firstName = :firstName WHERE c.id = :id")

En effet, JPQL souhaite que le nom de table de la requête corresponde au nom de votre classe d'entité.

Un autre problème pourrait être que l'annotation @Modifying manque:

@Modifying
@Query("UPDATE customer c SET c.firstName = :firstName WHERE c.id = :id")
  Integer setNewFirstNameForId(@Param("firstName") String firstName, @Param("id") long id);   
}

Chaque fois que vous souhaitez modifier par requête, vous devez ajouter l'anotation @Modifying car Spring doit en être informé.

18
Daris

Tenez également compte du fait que lorsque vous créez des requêtes personnalisées, vous devez utiliser la structure Entité et non la structure de base de données finale. Par exemple, vous pouvez avoir une clé privée composée. Ensuite, votre entité aurait un attribut qui serait l'entité avec les attributs conformes à la clé privée. Exemple:

@Entity(name = "itemPrice")
public class ItemPriceEntity {

    @EmbeddedId
    private ItemPriceComposedPK composedPK;

    // Rest of the fields
    ...

    // Getters and setters
    ...
}

@Embeddable
public class ItemPriceComposedPK implements Serializable {

   @Column
   private String id;

   @Column
   private int iteration;

   // Getters and setters
   ...
}

Si vous souhaitez utiliser le champ itération , vous devez coder quelque chose comme: i.composedPK.iteration. Exemple:

@Modifying
@Query("select i from itemPrice i where i.composedPK.iteration = :it")
public List<ItemPriceEntity> searchByIteration(@Param("it") String it);

Bien sûr, CrudRepository offre un meilleur moyen de faire cette requête sans utiliser de requêtes personnalisées mais, à titre d'exemple, c'est correct.

Cordialement!

2
Fulgencio Jara