当前位置: 首页 > 知识库问答 >
问题:

通用Spring数据JPA存储库findAll

孙辰阳
2023-03-14

是否有一种方法可以使通用Spring数据JPA存储库正确处理类似findall()的方法?例如animalrepository .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()同时返回水豚和狗。这个答案解释说:

这只有在域类使用单表继承时才起作用。我们在引导时能得到的关于domain类的唯一信息是它将是Product对象。因此,对于像findAll()甚至findByName(…)这样的方法,相关的查询将从select p from Product p where…开始。这是由于这样一个事实,即html" target="_blank">反射查找永远不能生成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(),那么拥有单个AnimalService的最干净的方法是什么?当然,一定有一个比我做的更好的方法,因为它变得非常丑陋,非常快,如果你有更复杂的服务和更多的动物。

编辑:鉴于Spring的DI认为animalrepository 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);
    }
}

也许有更好的办法,所以我会随时听取建议。

共有1个答案

冯新知
2023-03-14

关于存储库:由于您不使用单表继承,您将需要为每个t提供一个存储库实例,这是没有办法的。这意味着您将有一个animalrepository 的实例和一个animalrepository 的实例。

在服务上:在应用程序的某个地方,您将需要一个开关/案例,它根据类型将您引导到正确的存储库。

您有两个选项:a)拥有一个处理所有类型并在内部将查询定向到相应存储库的服务实例,或者b)为每个t拥有一个服务实例并在其他地方选择该实例。

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

由于类型擦除,在运行时获取对 的引用很混乱,但这是可以做到的。

 类似资料:
  • 我们正在研究一个包含大量DB表的Restful项目。虽然对这些表的操作几乎相同,主要是插入/更新/删除/提取(insert/update/delete/fetch)。 我的问题是: 我们是否必须为我们创建的每一个实体(域类)创建一个存储库(扩展JpaRepository),或者,有一个选项可以为所有实体创建一个能够处理上述所有功能的GenericRepository?即为所有人提供一个单一的Gen

  • 它是否将其存储在缓存中?我有一个应用程序,但应用程序中没有任何地方。属性是提到的db详细信息。我可以通过邮递员存储数据和查询它。

  • 对于方法,如果我发送空白,它可以工作,但值为null。而且,要搜索的字段太多了。所以我正在寻找一种更好的方法来搜索这样的表单。在Grails框架中,我可以为此创建名称,但在中没有找到更好的方法。 有什么想法吗?谢了。

  • 我正在尝试将通用Jpa规范与Spring启动一起使用,但出现了这个问题。 在我的代码中,我试图使用模块概念,所以我有5个模块(实体、dao、服务、web和前端,带角度),所以这是我的代码: 我的通用Jpa规范接口。 存储库示例。 服务 和控制器

  • 我们有许多通过接口扩展JpaRepository模式定义的存储库。当运行集成测试或应用程序的某些入口点时,我们只需要这些存储库的一个非常小的子集。 我们可以懒洋洋地加载实际的存储库隐含吗? 相当于@懒在@豆上的东西?注意:我至少尝试了用@lazy注释存储库接口的简单解决方案,但没有成功。

  • 又不想工作,我不知道是怎么回事。 日志包含以下消息: 将项目放在github https://github.com/romanych2021/testjpaspring上