JPA 清洁架构

Bar*_*son 7 java architecture design-patterns jpa

我正在根据Clean Architecture重构微服务:

在此处输入图片说明

框架应该在最顶层。所以我使用了Adapter Pattern和Dependency Inversion把它放在 org.springframework.data.repository.CrudRepository了最上层。但我怎么能使用@Entity(从Ĵ AVA P ersistence一个PI)坚持我的实体,如果实体是在中央和框架是在极其层?


示例:演示实体:

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class Demo implements Serializable {
    @Id
    @GeneratedValue
    private long id;
    
    @NotNull
    private String foo;

}
Run Code Online (Sandbox Code Playgroud)

GenericRepostioryInterface(在用例层)

public interface CrudRepositoryInterface<S,T> {
    public <U extends S> U save(U u) ;    
    public <U extends S> Iterable<U> saveAll(Iterable<U> itrbl) ;    
    public Optional<S> findById(T id) ;    
    public boolean existsById(T id) ;    
    public Iterable<S> findAll() ;    
    public Iterable<S> findAllById(Iterable<T> itrbl) ;    
    public long count() ;    
    public void deleteById(T id) ;    
    public void delete(S t);    
    public void deleteAll(Iterable<? extends S> itrbl) ;    
    public void deleteAll() ;  
}
Run Code Online (Sandbox Code Playgroud)

一些用例:

    @Autowired
    private CrudRepositoryInterface<Demo,Long> demoRepository;
    ...
    
    private void deleteAll(){
      this.demoRepository.deleteAll();
    }
    ...
Run Code Online (Sandbox Code Playgroud)

适配器(数据库层)

public interface DemoRepositoryAdapter extends CrudRepository<Demo,Long>,CrudRepositoryInterface<Demo,Long>{    
}
Run Code Online (Sandbox Code Playgroud)

注入配置(我也把它放在数据库包/层中)

@Configuration
public class InjectRepositoryConfig {    
    @Bean
    public CrudRepositoryInterface<Demo,Long> animalOwnerRepository(@Autowired DemoRepositoryAdapter demoRepositoryAdapter){
        return demoRepositoryAdapter;
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,这工作正常,但我不确定如何从核心层中删除/替换/重构 JPA?

Cor*_*ore 7

我认为这里的普遍混淆是由于术语实体的重载,它在不同的上下文中具有不同的语义。在 JPA 的上下文中,实体是表示表和 ORM 中行的持久性抽象。在 Clean Architecture 的上下文中,Entity 是业务域抽象,完全独立于持久性。

它们可以在 Clean Architecture 中共存,但它们各自都有不同的用途。尝试在您的业务领域实体中组合它们并利用 JPA 功能违反了清洁架构的原则,并将您的领域与您的持久性实现结合起来。

  • 我不知道为什么我的评论被否决了。请允许我引用《清洁架构》一书。第 198 页指出“您的实体对象应该是普通的旧对象,不依赖于框架或数据库或其他复杂性。” 第 215 页继续阐明“这样的 ORM 系统应该驻留在哪里?当然是在数据库层。” Cleary、JPA“实体”和 Clean Architecture“实体”是不同的。 (3认同)

小智 6

如果你真的想遵循干净的架构,那么你的域类中不应该引用外部库。为了克服这个问题,可以采用以下几种策略:

  • 用户 jpa/hibernate XML 映射。通过这种方式,您只需导入不同的配置文件(每个文件都将设置一组不同的 XML 映射),就可以轻松地外部化您的映射并在 sql/noSql 之间进行更改。

这种方法的缺点是,您的域仍然需要实现Serializable,并且其中大多数需要为其字段设置 setter/getter,或者强制 hibernate/jpa 忽略 Java 限制并访问私有字段。此外,您可以对 XML 无法使用的注释执行某些操作,或者解决方法存在问题。它可以工作,但您的域层仍然看起来像简单的 DTO。

  • 跨越边界时,使用 DTO 对象。这意味着您将拥有域对象Demo和一个 DTO 对象DemoData例如。将使用 DemoData 实例检索数据,并且存储库在保存/检索时应在这两者之间进行转换。

最后一种方法使您的项目很容易改变。您可以随时更改持久层,但这样做需要集成一个全新的数据存储层。假设您想更改为 cassandra,您将需要一个新的 DTO DemoDataCassandra、它与 Demo 之间的映射器、映射的新注释等。


Bra*_*rby 0

存储库保存实体的接口位于中心。该接口的实现位于外层,并且该实现被注入到需要的地方。