Java DDD何时应该创建域对象和持久性对象,而不是将持久性对象用作域对象?

Java DDD何时应该创建域对象和持久性对象,而不是将持久性对象用作域对象?,java,spring,jpa,domain-driven-design,ddd-repositories,Java,Spring,Jpa,Domain Driven Design,Ddd Repositories,随着我对领域驱动设计的理解,我发现我有一个似乎有效的规则,尽管我想看看它是否过火,也希望看到相同情况下的其他观点 我的问题是:“域模型和持久性模型什么时候应该包含在不同的对象中?” 目前我选择的语言是Java,我使用的是Spring数据的存储库模型 我的问题有三个主要答案 始终使用独立于持久性对象的域对象 仅当在持久性对象上放置域方法(行为)不实际时,才使用单独的域对象 在所有情况下都将持久性对象用作域对象 为了询问有关DDD的问题,我发现我必须使用一个示例限定上下文,因为我对DDD的了解还不够

随着我对领域驱动设计的理解,我发现我有一个似乎有效的规则,尽管我想看看它是否过火,也希望看到相同情况下的其他观点

我的问题是:“域模型和持久性模型什么时候应该包含在不同的对象中?” 目前我选择的语言是Java,我使用的是Spring数据的存储库模型

我的问题有三个主要答案

  • 始终使用独立于持久性对象的域对象
  • 仅当在持久性对象上放置域方法(行为)不实际时,才使用单独的域对象
  • 在所有情况下都将持久性对象用作域对象
  • 为了询问有关DDD的问题,我发现我必须使用一个示例限定上下文,因为我对DDD的了解还不够,无法以更抽象的方式提问

    以下是我的示例性有限上下文:假设我有一个具有以下业务规则的法律编纂系统:

  • 书上的每项法律都必须分类
  • 每项法律都有一个标识符,由两部分组成,一个编目编号前缀和一个编目协同号后缀。(示例:100-0100599-2030)
  • 有多个司法管辖区正在使用法律编纂系统,它们应该能够进行自己的协署,但编纂前缀是全球性的,并且在所有司法管辖区必须相同,以促进一般的可比性
  • 编目编号前缀分为广泛的编目类别。编目类别有一个数字范围,如100-199、200-299、700-799等
  • 要将此有界上下文表示为持久性模型,我有以下几点:

    table: codification
    fields: chart_code, prefix, coassign, codification_category
    
    table: codification_chart
    fields: chart_code, jurisdiction_description
    
    table: codification_category
    fields: category, low_category_number, high_category_number, description
    
    table: global_codification
    fields: prefix, coassign, codification_category
    
    我知道,我应该先从域模型开始。我有一个持久性模型和一个域模型

    在我的域模型中,我有三个域对象

    public Codification {
        private String prefix, coassign;
        codificationCategory codificationCaegory; // an enum type
        public Codification(...) { // set private vars }
        // getters for private variables
    }
    
    public CodificationChart {
        private List<Codification> chartCodifications = new ArrayList<>();
        private String chartCode;
        // public constructor to initialize private variables
        // getters for private variables
        public Codification addCodificationToChart(Codification){...}
        public void removeCodificationFromChart(Codification){...}
        public boolean checkCodificationInChart(Codification){...}
    }
    
    public enum CodificationCategory {
        CIVIL, CRIMINAL, PROPERTY, CORPORATE, FAMILY, CONSUMER, ETHICS, BANKRUPTCY;
    }
    
    我的域对象了解持久化模型的唯一一点是在我的工厂对象中,它具有我用来与前面提到的ORM对象交互的存储库接口。此工厂是域中唯一使用持久性存储库的部分,因此是唯一与持久性层交互的部分

    在这里创建一个单独的域模型是浪费精力吗? 我可以看到如何将编目chart行为放在持久性对象上。将这些行为放在持久性对象上感觉有些不对劲,持久性对象的唯一工作就是从数据库中检索记录


    我肯定会被纠正的

    这两种方法都是正确的,从设计的角度来看都是一种品味问题。有些人不希望他们的域对象与持久性有绝对的关系,而是创建了一个额外的
    实体层
    对象。。。有些人认为这不是一个大问题,他们很乐意继续使用域对象作为持久性对象

    就个人而言(主观上),我认为使用JPA并拥有一个额外的实体对象层是错误的方法。像Hibernate这样的ORM的目标是成为对象和关系模型之间的桥梁(我知道它的名字是:)。我认为一个更好的方法,如果你想把事情分开,就是使用mybatis或普通SQL,但绝对不是JPA。。。否则,它只是为了复杂性而增加复杂性(JPA不是最容易学习的框架)

    我很乐意接受混合和注释我的域对象。据我所知,它使持久性更容易管理。。。但同时,我对Hibernate/JPA感到非常舒服,并且已经使用了10年:)


    三年前我有一个非常类似的问题,我在程序员网站上发布了这个问题-

    谢谢你的观点。我有点害怕将领域和持久性混为一谈,因为我认为其他专业人士不会这么做。我会试试看我有多喜欢它。我同意,在使用JPA的情况下,分离显然是另一层复杂的东西,这不是严格必要的。我喜欢你对保持一致的回答。我想看到一个答案,有人主张将它们分开,这样我就可以看看在使用JPA的情况下是否有任何好的理由这样做。这也正是我的立场,感谢Augusto比我说得更好:)另外,我对Java知之甚少,但除了“侵入式”之外,难道没有其他选择吗JPA注释,其中映射细节将被外部化为某种“流畅的映射”文件(比如旧的XML ORM配置,但在代码中)?这将对持久性有很大帮助。@guillaume31 Hibernate仍然支持XML映射(许多年前,我有同事更喜欢这种方法,因此生产代码和映射之间没有静态关联)。我不知道有什么扩展可以在一个好的DSL中定义映射。。。但这可能是一个构建一个的问题(不幸的是,它是ORM特有的)。最后。。。我从未见过Java中数据访问是100%透明的应用程序,它总是一个泄漏的抽象。
    JPA Mappings of the tables mentioned earlier with the "Entity" suffix added to their table names. 
    They are omitted for brevity. 
    Each one contains getters and setters like JPA Pojos do. 
    If someone asks for the Persistence objects code I will post it.