Java JPA 模式:从实体生成数据传输对象 DTO 并将 DTO 合并到数据库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20981862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pattern for JPA: Generating Data Transfer Object DTO from Entity and merging DTO to database
提问by user3170740
I am looking for a good way to create Data Transfer Objects (DTO) from a JPA Entity and vice versa. I want to send the DTO as JSON to a client, then receive the modified DTO and save it back to the database. It would be the most ease to perform the merge method from the EntityManager on the received object after it has been parsed from JSON to it's Java class.?
我正在寻找一种从 JPA 实体创建数据传输对象 (DTO) 的好方法,反之亦然。我想将 DTO 作为 JSON 发送给客户端,然后接收修改后的 DTO 并将其保存回数据库。在将接收到的对象从 JSON 解析为它的 Java 类之后,从 EntityManager 对接收到的对象执行合并方法将是最容易的。?
For example there is the following Entity and the Rest method for saving the modified object:
例如,有以下 Entity 和 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;
}
This works fine as long as I send the whole Entity Class as JSON and receive the whole Entity back. Then the EntityManager will merge the modified object to the database. But when I only want to provide a subset of the Entity (like only name and address of the customer) there will be problems:
只要我将整个实体类作为 JSON 发送并接收整个实体,这就可以正常工作。然后 EntityManager 会将修改后的对象合并到数据库中。但是当我只想提供实体的一个子集(比如只有客户的姓名和地址)时,就会出现问题:
What would be the best way to create a subset of an Entity?
??? -Writing the DTOs for the Entity by hand? This will generate duplicate code for every subset of the entity, which has to be maintained.
How to merge a DTO which is a subset of an Entity, back to the database?
??? -Using the merge() method of the EntityManager doesn't work. At first the DTO is no entity hence it can't be merged. And Just creating an Entity from the DTO, will have some unset values in the Entity. After a merge the values will be NULL in the database.
创建实体子集的最佳方法是什么?
???- 手动为实体编写 DTO?这将为实体的每个子集生成重复的代码,必须对其进行维护。
如何将作为实体子集的 DTO 合并回数据库?
???- 使用 EntityManager 的 merge() 方法不起作用。起初,DTO 不是实体,因此无法合并。并且只是从 DTO 创建一个实体,实体中会有一些未设置的值。合并后,数据库中的值将为 NULL。
One idea I came up with, was to specify additional Entities for each subset I want to have for an entity. (Like a database view) This would be duplicate code, but it could solve the problem with the merging of the DTO to the database. (And maybe this code can be auto-generated)
我想出的一个想法是为我想要的实体的每个子集指定额外的实体。(如数据库视图)这将是重复代码,但它可以解决将 DTO 合并到数据库的问题。(也许这个代码可以自动生成)
For example the Entity CustomerView1 links to the same table as the Customer class, but only provides the name and address of the customer. It's a DTO for the real Customer class, which can be sent as JSON and modified outside of the server. This class can then also be merged to the database by the EntityManager.
例如,Entity CustomerView1 链接到与 Customer 类相同的表,但仅提供客户的姓名和地址。它是真正的 Customer 类的 DTO,可以作为 JSON 发送并在服务器外部进行修改。然后,这个类也可以通过 EntityManager 合并到数据库中。
@Entity
@Table(name="CUSTOMER")
public class CustomerView1 {
??? @Id
??? Long id;
??? @Version
??? Long version;
??? String name;
??? String address;
????
??? ??? ... Getter() and Setter()
}????
But I have doubts about this solution, I don't know if this will mess with the JPA's caching of Entities and may cause some problems. ????
但是我对这个解决方案有疑问,我不知道这是否会干扰JPA对实体的缓存并可能导致一些问题。???
My Question is, is there a pattern to solve code duplication for DTOs and merging the DTOs back to the database?
我的问题是,是否有一种模式可以解决 DTO 的代码重复问题并将 DTO 合并回数据库?
Or is there a library for this purpose? - Something, like auto-generation for the DTOs and copying the DTOs back to the real Entity, to make it possible to merge them with the EntityManager.
或者是否有为此目的的图书馆?- 某些东西,例如自动生成 DTO 并将 DTO 复制回真实实体,以便将它们与 EntityManager 合并。
回答by Diversity
Take a look at the Value Object design pattern which directly addresses your problem.
查看直接解决您的问题的值对象设计模式。
This tutorial gives a nice introduction to value objects.
本教程很好地介绍了值对象。
回答by Vlad Mihalcea
If the size difference between the entity and the DTO is not considerable, you can opt for sending the Entity.
如果实体和 DTO 之间的大小差异不大,您可以选择发送实体。
When using DTOs, to overcome concurrency issues like lost update, you have to incorporate the entity version in your DTO.
使用 DTO 时,要克服丢失更新等并发问题,您必须将实体版本合并到 DTO 中。
If you don't use the Entity version, and the underlying row is changed between the REST GET and PUT methods, you will override changes the end-user was not really aware of.
如果您不使用实体版本,并且在 REST GET 和 PUT 方法之间更改了基础行,您将覆盖最终用户并未真正意识到的更改。
Whenever I have to alter an Entity (Create, Update, Delete), I rely on the JPA and Hibernate Optimistic Locking mechanism.
每当我必须更改实体(创建、更新、删除)时,我都会依赖JPA 和 Hibernate Optimistic Locking 机制。
For UI lists, tables, search results DTOs are a viable option, since you are only interested in a projection of your originating Entity. This way you speed-up retrievals and you can benefit from other SQL features (window-functions) that are not supported by JPA.
对于 UI 列表、表格、搜索结果 DTO 是一个可行的选择,因为您只对原始实体的投影感兴趣。通过这种方式,您可以加快检索速度,并且可以从 JPA 不支持的其他 SQL 功能(窗口函数)中受益。
回答by Christian Beikov
Sounds like what you are describing is exactly what Blaze-Persistence Entity Viewshave been made for. The current release only has support for creating the read-model i.e. the model you are sending to the client, but the write model part is nearly done. Entity Views map between an interface/abstract class DTO representation and the entity model. The library leverages the mapping information as good as it can to implement all kinds of performance optimizations.
听起来您所描述的正是Blaze-Persistence Entity Views 的用途。当前版本仅支持创建读取模型,即您发送给客户端的模型,但写入模型部分已接近完成。实体视图映射接口/抽象类 DTO 表示和实体模型。该库尽可能利用映射信息来实现各种性能优化。