有没有办法让一个通用的Spring数据JPA存储库正确地处理以下方法
findAll()
? 例如
AnimalRepository<Dog>.findAll
只归还狗,而不是所有动物?或者至少,最好的解决方法是什么?
假设我有这个:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Animal extends BaseEntity {
...
}
@Entity
public class Dog extends Animal {
...
}
@Entity
public class Capybara extends Animal {
...
}
public interface AnimalRepository<T extends Animal> extends JpaRepository<T, Long> {
}
@Service("animalService")
public class AnimalServiceImpl<T extends Animal> implements AnimalService<T> {
private final AnimalRepository<T> animalRepository;
@Autowired
public AnimalServiceImpl(AnimalRepository<T> aR) {
this.animalRepository = aR;
}
@Override
public void save(T animal) {
animalRepository.save(animal);
}
@Override
public List<T> findAll() {
return animalRepository.findAll();
}
...
}
它几乎完美地工作,把每只动物都放在自己的桌子上,等等。唯一的问题是:
findAll()
退货
两者都有
水豚和狗。这
answer
解释:
这仅在域类使用单表继承时有效。我们在引导时可以获得的关于域类的唯一信息是它将是产品对象。因此,对于像findAll()甚至findByName()这样的方法,相关查询将从产品p where中的select p开始。这是因为反射查找永远无法生成Wine或Car,除非您为其创建一个专用的存储库接口来捕获具体的类型信息。
好吧,遗憾的是,有多个存储库而不是只有一个存储库的代码变得不那么干净了。但我仍然想保留一个AnimalService类。我就是这样做的:
@Service("animalService")
public class AnimalServiceImpl<T extends Animal> implements AnimalService<T> {
private final DogRepository dogRepository;
private final CapybaraRepository capybaraRepository;
@Autowired
public AnimalServiceImpl(AnimalRepository<T> aR) {
this.animalRepository = aR;
}
@Override
public void save(T animal) {
animalRepository.save(animal);
}
@Override
public List<T> findAllDogs() {
return dogRepository.findAll();
}
@Override
public List<T> findAllCapybaras() {
return capybaraRepository.findAll();
}
...
}
如果存储库真的无法处理
findAll()
根据类型
<T>
,拥有单一动物服务的最干净方式是什么?当然,肯定有比我做的更好的方法,因为如果你的服务更复杂,而且不止是一对动物,那么它会变得非常丑陋,非常快。
编辑:考虑到Spring的DI考虑
AnimalRepository<Dog>
and
AnimalRepository<Capybara>
as being the same thing
(将相同的存储库注入到使用Capybara one的服务和使用Dog one的另一个服务中),我必须为每个服务创建不同的存储库和服务(ESala answer的选项B):
@NoRepositoryBean
public interface AnimalRepository<T extends Animal> extends JpaRepository<T, Long> {
}
public interface DogRepository extends AnimalRepository<Dog> {
}
public interface CapybaraRepository extends AnimalRepository<Capybara> {
}
public abstract class AnimalService<T extends Animal> {
private final AnimalRepository<T> animalRepository;
AnimalService(AnimalRepository<T> repo) {
this.animalRepository = repo;
}
public void salvar(T palavra) {
animalRepository.save(palavra);
}
public List<T> findAll() {
return animalRepository.findAll();
}
}
@Service
public class DogService extends AnimalService<Dog> {
@Autowired
public DogService(DogRepository repo) {
super(repo);
}
}
@Service
public class CapybaraService extends AnimalService<Capybara> {
@Autowired
public CapybaraService(CapybaraRepository repo) {
super(repo);
}
}
可能还有更好的方法,所以我会接受建议。