Eugene
Eugene

Reputation: 5543

How to create repository for more than one entity?

I'm trying to create a simple web-site, which hosts topics and comments. I've begun with topics, and created repository for them:

package com.myProject.mvc3.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TopicRepository extends CrudRepository<Topic, Integer>{    
     public List<Topic> findAllByTopicTag(Tag currentTag);
} 

And I've defined the path for my repository in the servlet-context.xml:

jpa:repositories base-package="com.myProject.mvc3.repository"

Now, I'd like to include the comments in my repository, and the following code doesn't work:

package com.myProject.mvc3.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CommentRepository extends CrudRepository<Comment, Integer> {
    public List<Comment> findTopicComments(Topic topic);

}

My project doesn't build even. Can you give me an advice, how to create repositories for more than one entities (Topic class and Comment class are declared with @Entity)?

What i'm faciong:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'topicController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.epam.mvc3.service.CommentService com.epam.mvc3.controller.TopicController.commentService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commentService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.epam.mvc3.repository.CommentRepository com.epam.mvc3.service.CommentService.commentRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commentRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: No property find found for type class com.epam.mvc3.model.Comment org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293) org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290) org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192) org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895) org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425) org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:467) org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:483) org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:358) org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:325) org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127) javax.servlet.GenericServlet.init(GenericServlet.java:160) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928) com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:84) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539) org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:298) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) java.lang.Thread.run(Thread.java:722)

Upvotes: 1

Views: 6249

Answers (2)

Oleksandr Bondarenko
Oleksandr Bondarenko

Reputation: 2018

Just add By in findTopicComments so that it became findByTopicComments. Of course, this will work only if Comment entity has topicComments field or it has topic field which, in turn, has comments field.

Btw, you don't need @Repository annotation on Spring-data-jpa repositories.

Actually, if your query name doesn't match pattern ^(find|read|get)(\\p{Upper}.*?)??By from this class then the following occurs:

  • any of the prefixes such as get, 'read' and find won't be stripped and will be considered as the part of a JPQL query to generate. In this case you will get an exception: java.lang.IllegalArgumentException: No property find found for type class ....
  • if there's nothing to strip from your method name then it will be processed as if it had findBy prefix before.

Since this is not clear from docs I've created the issue in Spring Data Commons issue tracker.

Upvotes: 2

dimas
dimas

Reputation: 6073

Try to write your repositories in such way:

@Repository
public interface TopicRepository extends JpaRepository<Topic, Integer> >{    

     @Query("select topic from Topic topic where topic.topicTag.id=?1")
     public List<Topic> findAllByTopicTag(int topicTagId);
} 

@Repository
public interface CommentRepository extends JpaRepository<Comment, Integer> {

    @Query("select comment from Comment comment where comment.topic.id=?1")
    public List<Comment> findTopicComments(int topicId);
}

In this example I specify id of the entities as search criteria because usually they are used as foreign key. You can easily add additional search criteria if you need.

More details about query methods in Spring Data you can find in reference documentation.

Update

About your error stack trace - I think this error means that you don't specify your classes in persistent.xml.

There is also a way to not specify all classes in your persistent.xml -> look here and here for details.

Also with Spring you can easily configure your JPA project without persistent.xml file if you use full java config. For example:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    LocalContainerEntityManagerFactoryBean factoryBean = 
            new LocalContainerEntityManagerFactoryBean();

    factoryBean.setDataSource(dataSource());
    factoryBean.setPackagesToScan(new String[] {"com.dimasco.springjpa.domain"});

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setShowSql(true);
    //vendorAdapter.setGenerateDdl(generateDdl)

    factoryBean.setJpaVendorAdapter(vendorAdapter);

    Properties additionalProperties = new Properties();
    additionalProperties.put("hibernate.hbm2ddl.auto", "update");

    factoryBean.setJpaProperties(additionalProperties);


    return factoryBean;
}

As you can see in this example I simply define what packages to scan.

Upvotes: 1

Related Questions