簡體   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