Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/rest/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 保存后如何检索实体关系?_Java_Rest_Jpa_Spring Data Jpa_Hypermedia - Fatal编程技术网

Java 保存后如何检索实体关系?

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); 变量实

我正在开发一个以JPA/Hibernate作为数据访问层的RESTfulWebService。 域实体之间存在关系是非常常见的。例如,假设一个实体
产品
,它有一个
类别
实体

现在,当客户端
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问题。