繁体   English   中英

通用Spring数据JPA存储库findAll

[英]Generic Spring Data JPA Repository findAll

有没有一种方法可以使通用Spring Data 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() 同时返回水豚和狗。 答案说明:

仅当域类使用单表继承时,此方法才有效。 我们在引导时可以获得的有关域类的唯一信息是它将是Product对象。 因此,对于诸如findAll()甚至findByName(...)之类的方法,相关查询将从Product p其中...的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();
    }

    ...

}

如果存储库确实不能根据类型<T>处理findAll() ,那么拥有单个AnimalService的最干净方法是什么? 当然,必须有一种比我做的更好的方法,因为如果您在服务中具有更多的复杂性,并且有很多动物,那么它将变得非常丑陋,非常快。


编辑:考虑到Spring的DI认为AnimalRepository<Dog>AnimalRepository<Capybara>是同一件事 (将相同的存储库注入使用AnimalRepository<Capybara>的服务和使用Dog的服务),我不得不创建一个不同的对象它们各自的存储库和服务(@ESala答案的选项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);
    }
}

可能有更好的方法,所以我将保持开放的态度。

在存储库上:由于您不使用单表继承,因此您将需要为每个T都需要一个存储库实例,没有办法解决。 这意味着您将拥有AnimalRepository<Dog>的实例和AnimalRepository<Capybara> AnimalRepository<Dog>的实例。

在服务上:应用程序中的某个位置,您将需要一个开关/外壳,根据类型将您引导至正确的存储库。

您有2个选择,a)具有处理所有类型的单个服务实例,并在内部将查询定向到相应的存储库,或者b)具有每个T的服务实例并在其他位置选择该实例。

我更喜欢选项a)。 您可以通过获取对T类型的引用并使用开关/案例来选择适当的存储库,使当前的实现通过单个findAll()返回正确的类型。

由于类型擦除,在运行时获取对<T>的引用很麻烦,但是可以做到。

如何为动物添加类别属性/枚举

@Override
public List<T> findAll(Animal animal) {
    if(animal.getCategory() == "Dog") 
       return findAllDogs();
    if(animal.getCategory() == "Capybara") 
       return findAllCapybaras();
}

@Override
private List<T> findAllDogs() {
    return dogRepository.findAll();
}

@Override
private List<T> findAllCapybaras() {
    return capybaraRepository.findAll();
}

注意:也可以获取泛型的Class类型,但这有点棘手

如何获得泛型类型T的类实例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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