保存后如何检索实体关系? [英] How to retrieve entity relationships after save?

查看:76
本文介绍了保存后如何检索实体关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 spring-data 作为其数据访问层开发RESTful网络服务,由JPA/Hibernate支持. 域实体之间具有关系是很常见的.例如,假设一个实体Product具有 一个Category实体.

I'm developing a RESTful webservice with spring-data as its data access layer, backed by JPA/Hibernate. It is very common to have relationships between domain entities. For example, imagine an entity Product which has a Category entity.

现在,当客户端POST是JAX-RS方法的Product表示形式时.该方法用@Transactional注释,以将每个存储库操作包装在事务中.当然,客户端只发送已经存在的Categoryid,而不是整个表示,而只是引用(外键).

Now, when the client POSTs a Product representation to a JAX-RS method. That method is annotated with @Transactional to wrap every repository operation in a transaction. Of course, the client only sends the id of an already existing Category, not the whole representation, just a reference (the foreign key).

在这种方法中,如果我这样做:

In that method, if I do this:

entity = repository.save(entity);

变量entity现在具有仅设置id字段的Category.这并不令我感到惊讶.我没想到会通过保存(SQL插入)来检索有关对象的信息.但是我需要整个Product对象和相关实体才能返回给用户.

the variable entity now has a Category with only the id field set. This didn't surprise me. I wasn't expecting a save (SQL insert) to retrieve information on related objects. But I need the whole Product object and related entities to be able to return to the user.

然后我这样做了:

entity = repository.save(entity);
entity = repository.findOne(entity.getId());

也就是说,在持久化对象后,在同一事务/会话中检索对象.

that is, retrieve the object after persisting it, within the same transaction/session.

令我惊讶的是,变量entity没有任何改变.实际上,数据库甚至没有得到一个选择查询. 这与Hibernate的缓存有关.由于某种原因,在同一事务中,如果以前保留了该对象,则查找不会检索到整个对象图.

To my surprise, the variable entity didn't change anything. Actually, the database didn't even get a single select query. This is related with Hibernate's cache. For some reason, when in the same transaction, a find does not retrieve the whole object graph if that object was previously persisted.

使用Hibernate,解决方案似乎是使用session.refresh(entity)(请参见).有道理.

With Hibernate, the solution appears to be to use session.refresh(entity) (see this and this). Makes sense.

但是如何使用spring数据实现这一目标?

我想避免创建重复的自定义存储库.我认为此功能应该是spring数据本身的一部分(有些人已经在spring数据的论坛中进行了报告:

I would like to avoid to create repetitive custom repositories. I think that this functionality should be a part of spring data itslef (Some people already reported this in spring data's forum: thread1, thread2).

推荐答案

tl; dr

需要通过使用链接来明确Web层中实体之间的引用,并且不应将其隐藏在半填充的对象实例之后.持久层中的引用由对象引用表示.因此,应该有一个专门的步骤将一个(链接)转换为另一个(完全填充的对象引用).​​

References between entities in the web layer need to be made explicit by using links and should not be hidden behind semi-populated object instances. References in the persistence layer are represented by object references. So there should be a dedicated step transforming one (the link) into the other (the fully populated object reference).

详细信息

这样处理后端ID并假定封送绑定做正确的事情是一种反模式.因此,客户端应该宁愿使用链接并将链接交给服务器,以表明他们希望在已经存在的资源和将要创建的资源之间建立连接.

It's an anti-pattern to hand around backend ids as such and assume the marshaling binding doing the right thing. So the clients should rather work with links and hand those to the server to indicate they want to establish a connection between an already existing resource and one about to be created.

因此,假设您已通过/categories/4711公开了现有的Category,则可以将其发布到服务器:

So assuming you have the existing Category exposed via /categories/4711, you could post to your server:

POST /products
{ links : [ { rel : "category", href : "/categories/4711" } ],
  // further product data
}

服务器将实例化一个新的Product实例,并使用其他数据填充该实例,并最终填充关联,如下所示:

The server would the instantiate a new Product instance, populate it with additional data and eventually populate the associations as follows:

  1. 通过查找链接关系类型来确定要填充的属性(例如,此处的category属性.
  2. 从给定的URI中提取后端标识符
  3. 使用相应的存储库查找相关实体实例
  4. 在根实体上设置
  1. Identify properties to be populated by looking up the link relation types (e.g. the category property here.
  2. Extract the backend identifier from the given URI
  3. Use the according repository to lookup the related entity instance
  4. Set it on the root entity

因此在您的示例中,沸腾到:

So in your example boiling down to:

Product product = new Product();
// populate primitive properties
product.setCategory(categoryRepository.findOne(4711));
productRepository.save(product);

只需将这样的内容发布到服务器即可:

Simply posting something like this to the server:

POST /products
{ category : {
    id : 1, … },
  … 
}

由于许多原因而欠佳:

  1. 您希望持久性提供程序隐式地持久化Product实例,同时识别"所引用的Category实例(实际上仅由一个ID组成)并不意味着要持久化,而是使用已经存在的Category的数据?我会说,这真是不可思议.
  2. 本质上,您期望用来透明地处理您决定执行POST的方式,从而将用于POST到服务器的数据结构强加给持久层.这不是持久层的责任,而是Web层的责任. Web层的整个目的是通过使用表示形式和到后端服务的链接来减轻基于HTTP的协议的特征.
  1. You want the persistence provider to implicitly persist a Product instance and at the same time 'recognize' that the Category instance referred to (actually consisting of an id only) is not meant to be persisted but updated with the data of the already existing Category? That's quite a bit of magic I'd argue.
  2. You essentially impose the data structure you use to POST to the server to the persistence layer by expecting it to transparently deal with the way you decided to do POSTs. That's not a responsibility of the persistence layer but the web layer. The whole purpose of a web layer is to mitigate between the characteristics of an HTTP based protocol using representations and links to a backend service.

这篇关于保存后如何检索实体关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆