Java 保存后如何检索实体关系?
我正在开发一个以JPA/Hibernate作为数据访问层的RESTfulWebService。 域实体之间存在关系是非常常见的。例如,假设一个实体Java 保存后如何检索实体关系?,java,rest,jpa,spring-data-jpa,hypermedia,Java,Rest,Jpa,Spring Data Jpa,Hypermedia,我正在开发一个以JPA/Hibernate作为数据访问层的RESTfulWebService。 域实体之间存在关系是非常常见的。例如,假设一个实体产品,它有一个类别实体 现在,当客户端POSTs将Product表示形式转换为JAX-RS方法时。该方法用@Transactional注释,以将每个存储库操作包装到事务中。当然,客户端只发送已经存在的类别的id,而不是整个表示,只是一个引用(外键) 在该方法中,如果我这样做: entity = repository.save(entity); 变量实
产品
,它有一个类别
实体
现在,当客户端POST
s将Product
表示形式转换为JAX-RS方法时。该方法用@Transactional
注释,以将每个存储库操作包装到事务中。当然,客户端只发送已经存在的类别的id
,而不是整个表示,只是一个引用(外键)
在该方法中,如果我这样做:
entity = repository.save(entity);
变量实体
现在有一个类别
,只有id
字段集。这并不让我感到惊讶。我不希望通过save(sqlinsert)来检索相关对象的信息。但是我需要整个产品
对象和相关实体能够返回给用户
然后我做了这个:
entity = repository.save(entity);
entity = repository.findOne(entity.getId());
也就是说,在同一事务/会话中保存对象后,检索该对象
令我惊讶的是,变量实体
没有改变任何东西。实际上,数据库甚至没有得到一个select查询。
这与Hibernate的缓存有关。出于某种原因,当在同一事务中时,如果该对象以前被持久化,则查找不会检索整个对象图
使用Hibernate,解决方案似乎是使用会话.刷新(实体)
(请参阅和)。有道理
但是如何使用spring数据实现这一点呢?
我希望避免创建重复的自定义存储库。我认为这个功能应该是SpringDataitslef的一部分(有些人已经在SpringData论坛上报道过了:,)。tl;dr
web层中实体之间的引用需要通过使用链接来明确,并且不应隐藏在半填充对象实例后面。持久层中的引用由对象引用表示。因此,应该有一个专门的步骤将一个(链接)转换为另一个(完全填充的对象引用)
详细信息
这是一种反模式,可以像这样传递后端ID,并假设封送绑定做正确的事情。因此,客户机应该使用链接,并将这些链接交给服务器,以表明他们希望在现有资源和即将创建的资源之间建立连接
因此,假设您通过/categories/4711
公开了现有的类别
,您可以发布到您的服务器:
POST /products
{ links : [ { rel : "category", href : "/categories/4711" } ],
// further product data
}
服务器将实例化一个新的产品
实例,用其他数据填充它,并最终填充关联,如下所示:
通过查找链接关系类型(例如此处的类别
属性),确定要填充的属性
从给定URI提取后端标识符
使用相应的存储库查找相关实体实例
在根实体上设置它
因此,在您的示例中,可以归结为:
Product product = new Product();
// populate primitive properties
product.setCategory(categoryRepository.findOne(4711));
productRepository.save(product);
只需将类似的内容发布到服务器:
POST /products
{ category : {
id : 1, … },
…
}
由于许多原因,这是次优的:
您希望持久性提供程序隐式持久化产品
实例,同时“识别”引用的类别
实例(实际上仅由id组成)不是要持久化,而是用已经存在的类别的数据更新?我认为这是相当神奇的
本质上,您将用于向服务器发布的数据结构强加给持久层,希望它以透明的方式处理您决定发布的方式。这不是持久层的责任,而是web层的责任。web层的全部目的是缓解基于HTTP协议的特性之间的矛盾l使用后端服务的表示和链接
回答得很好!我们不是已经在单一资源URL中提供了后端id了吗,例如/categories/4711
?此外,我们需要解析链接的类别URL并获取其id。这应该由一些HATEOAS帮助程序或库提供。不确定如何优雅地完成。HATEOAS似乎比我想象的更广泛。:)我使用了/categories/4711
作为可读示例,但是URI可以是/fe6325a27
,我想这使得需要额外的映射步骤更加明显。在中,我们已经有了API来构建指向控制器方法和JAX-RS资源的链接实例。不幸的是,您是唯一知道在URI中的什么位置可以找到后端id的人(例如,/categories/4711
VS./categories?id=4711
。如上所示,即使是一个完整的映射步骤也可能是必要的。因此很难为其构建通用支持。我知道您是spring hateoas的贡献者。您能告诉我它对JAX-RS的支持有多好,特别是在ResourceAssembler方面吗?有没有任何示例JAX-RS可用?当JaxRsLinkBuilder尝试执行新的JaxRsLinkBuilder(ServletUriComponentsBuilder.fromCurrentServletMapping()时,我在JaxRsLinkBuilder中遇到了一些问题
。我得到无法通过RequestContextHolder找到当前请求。我过去曾尝试使用此库。它似乎可以很好地解决HATEOAS问题,但从未成功地将其与JAX-RS一起使用。只是找到了带有常规Spring contollers的示例存储库。我没有使用最新的Spring HATEOAS。我没有使用EntityLinks.是否可以在xml中@EnableEntityLinks
?我对如何在Spring+JAX-RS应用程序中使用编程配置有点迷茫。我应该子类化/实现哪个“WebInitializer”?也许我应该创建一个新的SO问题。