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

JPA模式:从实体生成数据传输对象DTO并将DTO合并到数据库

丁翊歌
2023-03-14

我正在寻找一种从JPA实体创建数据传输对象(DTO)的好方法,反之亦然。我想将DTO作为JSON发送到客户机,然后接收修改后的DTO并将其保存回数据库。在接收到的对象从JSON解析到它的Java类之后,从EntityManager对其执行merge方法将是最容易的。 

例如,有以下实体和用于保存修改html" target="_blank">对象的Rest方法:

@Entity
@Table(name="CUSTOMER")
public class Customer {
    @Id
    Long id;
    @Version
    Long version;
    String name;
    String address;
    String login;
    String password;
    String creditCardNumber;
    @OneToMany(cascade = CascadeType.ALL)
    List<Foo> fooList;

    ... Getter() and Setter()
}
private EntityManager em;
@POST
@Path("/saveCustomer")
public void saveCustomer ( Customer  customer)   {               
   em.merge(customer);
   return;
}  

只要我将整个实体类作为JSON发送并接收回整个实体,就可以很好地工作。然后EntityManager将修改后的对象合并到数据库中。但当我只想提供实体的一个子集(比如只提供客户的名称和地址)时,就会出现问题:

>

  • 创建实体子集的最佳方法是什么?

       -手写实体的DTO?这将为实体的每个子集生成重复的代码,而这些子集必须进行维护。

    如何将作为实体子集的DTO合并回数据库?

       -使用EntityManager的merge()方法不起作用。起初,DTO不是实体,因此不能合并。并且只是从DTO创建一个实体,在该实体中会有一些未设置的值。合并后,数据库中的值将为NULL。

    我想出的一个主意是,为我想要的实体的每个子集指定额外的实体。(如数据库视图)这将是重复的代码,但它可以通过将DTO合并到数据库来解决问题。(也许这段代码可以自动生成)

    例如,实体CustomerView1链接到与Customer类相同的表,但只提供客户的名称和地址。它是一个真实客户类的DTO,可以作为JSON发送并在服务器外部进行修改。然后,EntityManager还可以将该类合并到数据库中。

    @Entity
    @Table(name="CUSTOMER")
    public class CustomerView1 {
        @Id
        Long id;
        @Version
        Long version;
        String name;
        String address;
        
            ... Getter() and Setter()
    }    
    

    但是我对这个解决方案有疑问,我不知道这是否会扰乱JPA对实体的缓存,并可能引起一些问题。    

    我的问题是,是否有一种模式来解决DTO的代码重复并将DTO合并回数据库?

    还是有专门的图书馆?-一些东西,比如自动生成DTO并将DTO复制回真正的实体,使它们与EntityManager合并成为可能。

  • 共有2个答案

    汪庆
    2023-03-14

    看看直接解决问题的Value Object设计模式。

    教程很好地介绍了值对象。

    http://www.javastuff.in/2012/04/value-object-pattern.html

    黄元章
    2023-03-14

    如果实体和DTO之间的大小差异不大,则可以选择发送实体。

    当使用DTO时,为了克服丢失更新等并发问题,您必须将实体版本合并到DTO中。

    如果您不使用实体版本,并且底层行在REST GET和PUT方法之间发生了更改,那么您将覆盖最终用户并不真正意识到的更改。

    每当我必须更改一个实体(创建、更新、删除)时,我都依赖于JPA和Hibernate乐观锁定机制。

    对于UI列表、表、搜索结果,DTO是一个可行的选项,因为您只对原始实体的投影感兴趣。这样可以加快检索速度,并且可以从JPA不支持的其他SQL特性(窗口函数)中获益。

     类似资料:
    • 问题内容: 我最近听到有人说数据传输对象(DTO)是一种反模式。 为什么?有哪些选择? 问题答案: 一些项目的所有数据都有两次。一次作为域对象,一次作为数据传输对象。 这种重复需要付出巨大的代价,因此该架构需要从这种分离中获得巨大的收益,才能使其值得。

    • 问题内容: 在我的DAO层中,我有一个类似的Find函数 因此,为了读取数据,我必须使用Loop(带有) 我的问题是:是否有任何api框架可以轻松地将其转换为对象列表(例如DQCategoryDTO),而无需使用任何循环,迭代器和调用setter / getter来填充值? 问题答案: 您可以使用ResultTransformer,它可以从别名转换为bean(DTO)属性。对于用法,您可以在此处的

    • 在我的Spring Boot项目中,我使用Hibernate,基本上我们有三种对象 在控制器层中使用的DTO对象 业务对象—业务对象是我们在整个应用程序中使用的对象 实体/域对象-用于JPA层 当我们准备好保存数据时,我们将业务对象转换为域/实体对象 当我们准备将其发送给客户机/控制器时,我们可以将实体对象转换为业务对象,然后将此业务对象转换为DTO对象。 理想情况下,我被告知将BOs更改为- 我

    • 问题内容: 我们将使用DTO在表示层之间来回发送数据。我们有像这样的图层: facade appService domain 并且我们使用推土机来帮助我们将实体转换为dto。但是我现在有两个问题: 从实体到dto,我们可以使用推土机,但是从dto到实体,我们可以使用推土机吗?如果是,如何? 我应该在哪里创建实体?在外观或DTOAssembler中? 例如,我必须注册一本书。这本书的实体外观如下:

    • 问题内容: 我正在使用 MapStruct 进行映射。相同的映射器用于从dto 创建 和 更新 实体。完成dto的id验证,以了解是否必须创建一个新实体(id == null)还是应该从数据库中检索它(id!= null)。 我实际上正在使用MapperDecorator作为解决方法。范例: 映射器 装饰器 但是,由于必须为每个映射器创建一个装饰器,因此该解决方案变得繁重。 有什么好的解决方案吗?