【问题标题】:Jackson seemingly not persisting bidirectional relationship managed by Hibernate杰克逊似乎没有坚持由 Hibernate 管理的双向关系
【发布时间】:2015-08-25 04:10:46
【问题描述】:

当我将 JSON 对象发布到我的 REST API(使用 Spring 和 Hibernate)时,我无法弄清楚为什么关系的拥有方没有在另一方持续存在。

带有id字段的映射超类:

@MappedSuperClass
public class BaseEntity implements Serializable {
    private static final long serialVersionUID = 11538918560302121L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    ....
    }

拥有类(扩展NamedEntity,而后者又扩展BaseEntity):

@Entity
@DynamicUpdate
@SelectBeforeUpdate
@NamedQuery(name = "Chain.byId", query = "from Chain where id=:id")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope=Chain.class)
public class Chain extends NamedEntity {
    private static final long serialVersionUID = 4727994683438452454L;
    @OneToMany(mappedBy = "chain", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<Campaign> campaigns = new ArrayList<Campaign>();
    ....
}

所属类:

@Entity
@DynamicUpdate
@SelectBeforeUpdate
@NamedQuery(name = "Campaign.byId", query = "from Campaign where id=:id")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope=Campaign.class)
public class Campaign extends NamedEntity {
    @ManyToOne
    @JoinColumn(name = "chain_id")
    private Chain chain;
    ....
}

我的RestController的相关部分:

@RequestMapping(value = "new", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@ResponseBody
public Chain saveChain(@RequestBody Chain chain) {
    chainDAO.saveChain(chain);
    return chain;
}

JSON 请求正文:

{  
  "name": "mcdonald's",
  "campaigns": [
      {
          "name": "summer1"
      }
  ]
}

JSON 响应正文的相关部分:

{
  "id": 1,
  "name": "mcdonald's",
  "campaigns": [
    {
      "id": 1,
      "name": "summer1",
      "rewards": [],
      "startDate": null,
      "endDate": null,
      "chain": null,
      "surveys": [],
      "achievements": []
    }
  ],
  "rewards": []
}

我怀疑这实际上是使用 @JsonIdentityInfo 注释打破无限递归时的预期行为?但是,当我尝试请求刚刚使用其 id 字段创建的 Chain 时,我看不到嵌套对象(Campaign ) 了。

我用来检索我刚刚创建的 Chain 对象的 GET 方法:

@RequestMapping(value = "{id}", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Chain getChain(Model model, @PathVariable int id) {
    Chain chain = chainDAO.getChainById(id).get(0);
    return chain;
}

GET 方法的 JSON 响应正文:

{
  "id": 1,
  "name": "mcdonald's",
  "campaigns": [],
  "rewards": [],
  "managers": [],
  "locations": []
}

如您所见,这个 Chain 对象中的 campaigns 数组现在是空的。

【问题讨论】:

    标签: java json spring hibernate jackson


    【解决方案1】:

    原来我只是没有正确管理双向关系。必须在两端显式设置关系。

    @RequestMapping(value = "{id}/campaigns/new", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
        @ResponseBody
        public Campaign saveCampaignToChain(@RequestBody Campaign campaign, @PathVariable int id) {
            Chain chain = chainDAO.getChainById(id).get(0);
            chain.getCampaigns().add(campaign);
            campaign.setChain(chain);
            chainDAO.saveChain(chain);
            campaignDAO.saveCampaign(campaign);
            return campaign;
        }
    

    【讨论】:

    • 但这意味着在保存新记录之前,您必须先查询数据库。这不是有点开销吗?
    • 是的。从那以后,我不再在这个项目中完全使用 ORM,因为我发现以编程方式设置数据库关系比手动编写 SQL 查询更麻烦。
    • 我明白了。那么你最终使用了什么?
    • 我发现了一个名为 PostgREST 的项目,它为任何 PostgreSQL 数据库实现了一个 REST API,并将 API 和数据库都部署为 Docker 容器。然后我从 Java 切换到 Go 来编写实现客户业务逻辑所需的任何中间件。 Go 是一种较小的语言,让我可以专注于手头的问题,而不用担心 Spring 和 Hibernate 等框架引入的抽象。它还像冠军一样处理 JSON 编码/解码,它的内置库对我来说已经足够了,它还让实现 for 循环的并行处理变得轻而易举。
    • 感谢您的信息。我解决了我的问题。我用于将 Campaign 链接到链的外键未使用 [@]Id 进行注释。没有它,hibernate 不会在 Chain 表中查找它,而是根据级联规则创建一个新的。 tl:博士;如果在另一边注释了 [@]Id,外键将起作用。
    猜你喜欢
    • 1970-01-01
    • 2017-06-06
    • 2019-02-24
    • 1970-01-01
    • 2013-04-11
    • 2016-04-04
    • 2012-07-21
    • 2017-04-20
    • 1970-01-01
    相关资源
    最近更新 更多