如何将Web服务的输入合并到JPA实体

Ben*_*ley 7 java rest jpa jax-rs dto

我试图找出在宁静的Web服务环境中使用JPA的最佳方法.输入以JSON形式出现,我可以使用Jackson/JAX-RS将其转换为POJO.这将传递给我需要以某种方式合并到JPA实体的服务.

这些是我迄今为止发现的有利有弊的选择.

1. JPA merge()
我尝试的第一件事可能是最简单的.GET操作返回JPA实体,该实体很容易序列化为JSON.在更新时,传回的对象是JSON,可用于填充分离的实体.可以使用JPA merge()方法将其保存到DB.

优点
简单的架构,代码重复较少(即没有DTO)

缺点
据我所知,这只有在你传递整个模型时才有效.如果您尝试隐藏某些字段,例如可能是User实体上的密码,那么合并会认为您尝试在DB中将这些字段设置为null.不好!

2. DTO使用JPA find()和dozer
Next我认为我会考虑使用数据传输对象.显然是反模式,但值得一看.该服务现在基于实体创建DTO实例,并且此DTO被序列化为JSON.然后,更新使用find()方法从DB获取实体,并且需要将值从DTO复制到实体.我尝试使用dozer框架自动化这个映射.

优点
您无需返回整个模型.如果您有某些字段您不想更新,则可以将它们从DTO中删除,并且不能将它们错误地复制到实体.使用dozer意味着您不必手动将属性从dto复制到实体,反之亦然.

缺点
在编写DTO时,感觉就像重复自己一样.不知何故,你必须在实体和DTO之间进行映射.我试图用推土机自动化这个但是有点令人失望.它取消了应该没有的东西,并且要完全控制你必须编写xml.

3. DTO使用手动合并
第三种方式是放弃推土机,只需将属性从DTO复制到服务中的实体.每个人似乎都说反模式,但它几乎就是我过去看过的每一个非平凡的应用程序都是如此.

总结
似乎是在为开发人员保持简单但不控制输入/输出或制作更强大的Web服务但在过程中必须使用反模式之间做出决定...

我错过了什么吗?也许这是一个难以捉摸的选择?

Sha*_*dra 2

使用 JPA合并看起来是最简单、最干净且花费很少的工作,但正确发现会产生将分离实体属性设置为 null 的问题。在我的一次经历中,另一个很严重的问题是,如果您依赖 JPA 合并操作,那么您也必须使用 Cascade 功能。对于简单且嵌套较少的关系,这种方法效果相当好,但对于深度嵌套的域对象和大量关系,这会对性能产生很大影响。原因是 ORM 工具(根据我的经验,Hibernate)会预先缓存 SQL 来加载合并实体(Hibernate 术语中的“合并路径”),如果级联映射的嵌套太深,则 SQL 中的联接就会变得太大。标记关系惰性在这里没有帮助,因为合并路径是由关系中的级联决定的。随着模型的发展,这个问题会慢慢变得明显。再加上愤怒的 DBA 在我们脸上挥舞着巨大的连接查询的前景促使我们做一些不同的事情:-) 有一个与 Hibernate 有关的关于惰性关系合并的有趣问题仍未解决(实际上被拒绝,但讨论读起来非常愉快)在休眠 JIRA 中。

然后,我们转向 DTO 方法,避免使用合并,而是依靠手动执行。是的,这很乏味,并且需要了解独立实体实际上来自什么状态,但对我们来说这是值得的。这样我们就不会触及不打算改变的惰性关系和属性。并仅设置所需的内容。Hibernate 的自动状态检测会在事务提交时完成剩下的工作。