当前位置: 首页 > 面试题库 >

在Spring Data JPA存储库中使用泛型

时向文
2023-03-14
问题内容

我有许多需要保留到数据库的简单对象类型。我正在使用Spring JPA来管理这种持久性。对于每种对象类型,我需要构建以下内容:

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

public interface FacilityRepository extends JpaRepository<Facility, Long> {
}


public interface FacilityService {
    public Facility create(Facility facility);
}

@Service
public class FacilityServiceImpl implements FacilityService {

    @Resource
    private FacilityRepository countryRepository;

    @Transactional
    public Facility create(Facility facility) {
        Facility created = facility;
        return facilityRepository.save(created);
    }
}

在我看来,有可能用三个基于泛型的类替换每种对象类型的多个类,从而节省了大量的样板代码。我不确定该怎么做,实际上,如果这是个好主意?


问题答案:

首先,我知道我们在这里提高了一些标准,但这已经比没有Spring Data JPA的帮助而编写的代码少得多。

其次,如果你要做的只是将调用转发到存储库,那么我首先就不需要服务类。如果你有需要在事务中编排不同存储库的业务逻辑或要封装的其他业务逻辑,我们建议在存储库前面使用服务。

一般来说,你当然可以执行以下操作:

interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {

    @Query("select p from #{#entityName} p where ?1 member of p.categories")
    Iterable<T> findByCategory(String category);

    Iterable<T> findByName(String name);
}

这将允许你像这样使用客户端上的存储库:

class MyClient {

  @Autowired
  public MyClient(ProductRepository<Car> carRepository, 
                  ProductRepository<Wine> wineRepository) { … }
}

它将按预期工作。但是,有一些注意事项:

仅当域类使用单表继承时,此方法才有效。我们在引导时可以获得的关于域类的唯一信息是它将是Product对象。因此,对于类似的方法findAll(),甚至findByName(…)相关查询都将以开头select p from Product p where…。这是由于以下事实:反射查找将永远无法生成,Wine或者Car 除非你为其创建专用的存储库接口以捕获具体的类型信息。

一般而言,我们建议为每个聚合根创建存储库接口。这意味着你本身没有每个域类的存储库。更重要的是,基于存储库的服务的1:1抽象也完全没有意义。如果你构建服务,则不会为每个存储库都构建一个服务(猴子可以做到,而我们不是猴子,对吗?;)。服务正在公开一个更高级别的API,更多地是用例驱动,并且通常协调对多个存储库的调用。

另外,如果你在存储库之上构建服务,通常需要强制客户端使用服务而不是存储库(此处的经典示例是,用于用户管理的服务还会触发密码生成和加密,因此决不会最好让开发人员直接使用存储库,因为他们可以有效地解决加密问题。因此,你通常希望对谁可以保留哪些域对象保持选择性,而不是在整个地方都没有创建依赖项。

摘要
是的,你可以构建通用存储库并将其与多种域类型一起使用,但是存在相当严格的技术限制。但是,从架构的角度来看,你上面描述的场景甚至都不会弹出,因为这意味着你无论如何都面临着设计的气味。



 类似资料:
  • 我突然想到,可以用三个基于泛型的类来替换每个对象类型的多个类,从而节省大量的样板代码。我不是很清楚该怎么做,事实上这是不是一个好主意?

  • 我正在使用100个实体(使用JHipster)设置一个新的Spring Boot API,我的问题是:鉴于我有一组存储库层方法,我希望我的所有存储库都能够调用这些方法。 我已经尝试制作所有接口来扩展('RepositoryQuery'是我默认的自定义接口名称后缀),然后使用特定于实体的类。请注意,所有的类扩展了一个泛型实现类,名为。 请注意,给定正则表达式中的“.*”代表我的持久实体集中的任何实体

  • 使用laravel 7/livewire应用程序,我使用Repository制作crud,并获得了数据列表,在装载事件中,我分配了受保护的var$FacilityRepository,它在render方法中正常工作, 但在编辑方法中为空,我得到错误: 当用户单击“编辑链接”时 在模板中,编辑链接定义为: 为什么会出现错误以及如何修复? 修改#2: > 类设施扩展组件{...公共$FacilityR

  • 我在Spring Boot中创建了一个实用程序,以更通用的方式将数据连接和插入/更新到沙发底座中。 我有这样的东西: 在我有的地方,我想接受任何类型的文档插入沙发底座。 我尝试过一些方法,比如使用泛型类型T,但没有成功,因为我遇到了以下错误: 原因:org。springframework。数据地图。MappingException:找不到类型类java的PersistentEntity。朗,反对!

  • 我正在尝试实现一个简单的REST服务,该服务基于具有Spring启动和Spring数据Rest的JPA存储库。(请参阅此教程)如果将以下代码与 gradle 一起使用,则运行良好: 为了让事情变得更简单,我使用Spring boot CLI(“Spring run”命令)尝试了相同的代码。 不幸的是,这似乎不起作用@RepositoryRestResource似乎无法像@RestControlle

  • 我正在升级一个扩展,以使用TYPO3 v10。由于命令控制器不能再使用,我将它们迁移到由留档指向的symfony命令。除了使用extbase存储库类之外,一切都非常顺利。无论我查询什么,我从来没有得到一个结果。因为我找不到任何有用的信息在网上和留档我希望这可能只是一些次要的。 调试一段时间后,我发现pid在构建查询设置时没有正确确定。我发现这种奇怪,因为我的根模板有这些行: injectMyRep