web-dev-qa-db-ja.com

CrudRepositoryを使用したカスタムクエリ

CrudRepositoryを使用してクエリをカスタマイズしたいと思います。

これは私のコードです:

@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);
    }

しかし、これをすべてコンパイルすると、エラーの抜粋が次のようになります。

よろしくお願いいたします。

編集:

これは私のエラーです:

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

最初の問題はJPQLにあります。

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

入力する

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

これは、JPQLがクエリのテーブル名をエンティティクラス名と一致させたいためです。

もう1つの問題は、@ Modifyingアノテーションがないことです。

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

クエリで変更するたびに、@ Modifyingアノテーションを追加する必要があります。これは、Springがそれを認識する必要があるためです。

18
Daris

また、カスタムクエリを作成するときは、最終的なデータベース構造ではなくエンティティ構造を使用する必要があることも考慮してください。たとえば、合成された秘密鍵を持つことができます。次に、エンティティには、秘密鍵に準拠する属性を持つエンティティである属性があります。例:

@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
   ...
}

フィールドiterationを使用する場合は、i.composedPK.iterationのようにコーディングする必要があります。例:

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

もちろん、CrudRepositoryは、カスタムクエリを使用せずにこのクエリを作成するより良い方法を提供しますが、例としては問題ありません。

よろしく!

2
Fulgencio Jara