简体   繁体   中英

Is it wrong to @Inject the repository in a custom repository (Spring Data JPA)

I want to build complex queries inside my custom repository, but since custom repository doesn't extend the "simple" repository (but the other way around) I don't have access to the findXxx methods of the repository, so I am @Injecting the "simple" repository. It works just fine, but it sure doesn't look good. I'm doing this because I don't want to have another "service" class in front of my repository to handle the complex queries. I want them to be nicely packed inside the Repository class.

Let me explain with some code:

PersonRepository.java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;

public interface PersonRepository extends JpaRepository<Person, Long>, QueryDslPredicateExecutor<Person>, PersonRepositoryCustom {
}

interface PersonRepositoryCustom {
    Page<Person> complexSearch(Person example, Pageable pageable);
}

PersonRepositoryImpl.java

import javax.inject.Inject;
import com.mysema.query.types.expr.BooleanExpression;

public class PersonRepositoryImpl implements PersonRepositoryCustom {

    @Inject
    private PersonRepository repository; // <<<--- This is weird, but works!

    @Override
    public Page<Person> complexSearch(Person example, Pageable pageable) {
        QPerson p = QPerson.person;
        BooleanExpression e = p.id.isNotNull();
        if (example.getName() != null) {
            e = p.name.like("%" + example.getName() + "%");
        }
        if (example.getDob() != null) {
            e = e.and(p.dob.isNotNull()).and(p.dob.after(example.getDob()));
        }
        return repository.findAll(e, pageable); // <<<--- This is weird, but works!
    }

}

So then, I just directly use my repository for example from a controller:

PersonController.java

import javax.inject.Inject;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/")
public class PersonController {

    @Inject
    private PersonRepository personRepository;

    @ResponseBody
    @RequestMapping(value = "/people/search", method = RequestMethod.POST)
    public Page<Person> buscaCampañas(Pageable pageable, @RequestBody Person example) {
        return personRepository.complexSearch(example, pageable);
    }
}

Everything works just fine, but I just wan't to make sure I'm not shooting myself in the foot.

From a technical point of PersonRepositoryImpl and SimpleJpaRepository are two distinct spring beans which are eligible for normal dependency injection into each other. From a design point of view I don't see any serious issues with your approach. Imho, your approach is more like a self invocation of another method within the same object. Just replace repository with this in your mind.

You could also introduce a service layer that combines several repositories or your query code into a higher level class. In future, rather than modify your client code you could easily replace your relational search by real search engine in your service.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM