Jackson双向关系(一对多)不起作用

4
我将为您翻译如下内容,这是关于IT技术的:

在这个web服务项目中,我使用了Spring(xml+annotations)和Hibernate(annotations)。以下是数据库关系图、模型以及期望和实际输出:

数据库表关系

Customer.java

@Entity
@Table(name="customer")
public class Customer implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="customer_id", unique=true, nullable =false)
    long customerId;
    @Column(name="name")
    String name;
    @Column(name="secondary_name")
    String secondaryName;
    @Column(name="date")
    Date date;
    @Column(name="address")
    String address;
    @Column(name="post")
    String post;
    @Column(name="pin")
    String pin;
    @Column(name="phone")
    String phone;
    @OneToMany(fetch=FetchType.LAZY, mappedBy="customer", cascade=CascadeType.ALL)
    @JsonManagedReference
    Set<Loan> loans = new HashSet<Loan>();
    //constructors, getters and setters
}

Loan.java

public class Loan implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="loan_id", nullable=false, unique=true)
    long loanId;
    @ManyToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinColumn(name="customer_id", nullable = false)
    @JsonBackReference
    Customer customer;
    @Column(name="date", nullable=false)
    Date date;
    @Column(name="amount", nullable=false)
    double amount;
    @OneToMany(fetch=FetchType.LAZY, mappedBy="loan", cascade=CascadeType.ALL)
    @JsonManagedReference
    List<Item> items = new ArrayList<Item>();
    //constructors, getters, setters
}

Item.java

public class Item implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="item_id", nullable=false, unique=true)
    long itemId;
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="loan_id", nullable = false)
    @JsonBackReference
    Loan loan;
    @Column(name="name", nullable=false)
    String name;
    @Column(name="weight", nullable=false)
    double weight;
    //constructors, setters, getters
}

实际输出:这里没有显示客户详细信息。
{  
   "loanId":4,
   "date":1484937000000,
   "amount":10000.0,
   "items":[  
      {  
         "itemId":3,
         "name":"Item1",
         "weight":10.0
      },
      {  
         "itemId":4,
         "name":"Item2",
         "weight":20.0
      }
   ]
}

预期输出:在寻找贷款时需要展示客户详细信息。
{  
   "loanId":4,
   "customer":{  
      "customerId":2,
      "name":"Prem",
      "address":"Street,State"
   },
   "date":1484937000000,
   "amount":10000.0,
   "items":[  
      {  
         "itemId":3,
         "name":"Item1",
         "weight":10.0
      },
      {  
         "itemId":4,
         "name":"Item2",
         "weight":20.0
      }
   ]
}

我可以从数据库中获取客户详细信息,但使用Jackson Json无法加载它。 如果我删除@JsonManagedReference,则会产生循环引用。 如果我删除@JsonBackReference,则输出没有影响。 完整的代码在:https://github.com/liwevire/TM_Service 提前致谢。

3个回答

16
因为您在Loan实体中的Customer属性上使用了@JsonBackReference,所以Customer对象不会被包含在序列化中。请在Loan对象中使用@JsonManagedReference来处理Customer,并在Customer实体的Loan属性上使用@JsonBackReference
这将序列化您的Loan实体中的Customer属性。但是,Customer对象序列化将不包含Loan属性。您需要选择一侧关系进行序列化。
如果要允许双向关系,请在实体中使用@JsonIdentityInfo注释,并删除@JsonBackReference@JsonManagedReference。您的实体将类似于:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "customerId")
public class Customer implements Serializable {
    ...
}

@JsonIdentityInfoproperty 属性是指您实体的 id 属性,对于 Customer,这将是 customerId。 对于 LoanItem 也是如此。


1
输出如下: {"loanId":2,"customer":{"customerId":1,"name":"Premkumar","secondaryName":"T","date":1484663297000,"address":"Sethu Road","post":"PVI","pin":"614804","phone":"9876543210","loans":[2,{"loanId":3,"customer":1,"date":1484591400000,"amount":20.0,"items":[{"itemId":2,"loan":3,"name":"L2","weight":1.0}]},{"loanId":4,"customer":1,"date":1484937000000,"amount":10000.0,"items":[{"itemId":3,"loan":4,"name":"Item1","weight":10.0},{"itemId":4,"loan":4,"name":"Item2","weight":20.0}]}]},"date":1484591400000,"amount":40.0,"items":[{"itemId":1,"loan":2,"name":"PT1","weight":1.0}]} - liwevire
1
@W-S 对于第一次出现,它正在构建整个对象,而对于下一次出现,它正在引用该ID。但我想要整个对象。怎么做? - Krish
1
@liwevire,你误解了我的意思。我想问的是,对于特定的企业,我们可以获取组织(唯一记录)列表。但是,如果我想从子级遍历,它就不能正常工作,即列出与企业相关的组织列表。对于第一个企业的出现,它正在构建整个企业对象,并且对于下一个出现(org1和org2与Ent1相关联),它正在引用该ID。但我想要整个对象。如何实现? - Krish
1
@liwevire 不,我们的工作是实现API并将其分发给多个客户端。我不能要求他们使用这些ID引用。有没有办法避免这些ID并在两个方向(父->子,子->父)中获取整个对象?这对我非常有帮助。 - Krish
2
经过多次尝试,@JsonIgnoreProperties 解决了我的问题。 - Krish
显示剩余10条评论

1
这里是一个比较冗长的方法。但需要对您的应用程序进行一些设计修改。 我遇到了类似的问题,为每个实体类创建了单独的pojo。
在服务层中,我使用这些pojo作为参数而不是实体对象,并使用适当的getter/setter将属性设置/获取到实体类中。 通过这种方式,您可以获取/设置所需的属性并避免不需要的属性。但是,我在DAO层实现了额外的方法来获取相关实体。这是一个非常冗长的方法,但对我解决了这个问题。

1

这似乎很陈旧,但让我也在这里放置我的硬币;我会将实体和模型分离。意思是:

> Client <-> Application : Models
> 
> Application <-> Database : Entities

您的服务层或任何处理数据的层应该在实体和模型之间进行转换。

  1. 通过按照您的意愿返回数据来摆脱递归。
  2. 将定义分成两个不同的通信渠道。这样,您可以决定向客户端展示什么以及如何展示给客户端。这样可以避免直接暴露数据库架构。
  3. 您可以根据自己的需要扩展模型,而无需触及后端数据库。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接