Spring Boot实体多对一映射在嵌入对象中

huangapple go评论43阅读模式
英文:

Spring boot entity many to one mappping in embaded object

问题

我正在构建一个简单的Spring Boot博客应用程序。该应用程序有两个实体:用户(user)和帖子(post)。用户表保存用户数据,主键为Id,帖子表保存内容信息,用户信息作为外键"postedBy",它引用用户表的id。一个用户可以有多个帖子。

基于此,我设计了以下实体类。

@Entity
@Table
public class User {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String name;
    private String email;
}

@Entity
@Table
public class Post {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String title;
    @ManyToOne
    @JoinColumn(name = "id", insertable = false, updatable = false)
    private User postedBy;
    private String content;
}

由于用户可以有多个帖子,我使用了@ManyToOne注解,通过@JoinColumn映射到用户的id。

我正在使用JpaRepository接口,然后通过REST控制器暴露它。

但是,当我发送如下的帖子插入请求体时:

{
	"title":"The Graphql way of design",
	"postedBy":"402880ee73aa45570173aa462ea00001",
	"content":"The content of the blog"
}

它抛出以下错误:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001')
 at [Source: (PushbackInputStream); line: 3, column: 13] (through reference chain: com.graphql.blog.model.Post["postedBy"])]

我预期postedBy列将存储"402880ee73aa45570173aa462ea00001",因为用户已经存在,并且在响应中,它将自动获取该帖子的用户详细信息。

英文:

I am building a simple spring boot blog app. This app has two entities user and post. The user table holds user data and has the primary key as Id and the post table holds content information with user information as a foreign key "postedBy" which refers to the id of user table. One User can have many posts.

Based on this I have designed Entity class like below.

Spring Boot实体多对一映射在嵌入对象中

@Entity
@Table
public class User {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String name;
    private String email;
}


@Entity
@Table
public class Post {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String title;
    @ManyToOne
    @JoinColumn(name = "id" , insertable = false,updatable = false)
    private User postedBy;
    private String content;
}

As a user can have multiple posts I have user @ManyToOne annotation which maps to id of user via @JoinColumn

I am using the JpaRepository interface which is then exposed via rest controller.

But when I send the body to insert post like below

{
	"title":"The Graphql way of design",
	"postedBy":"402880ee73aa45570173aa462ea00001",
	"content":" The content of blog "
}

It throws below error

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001')
 at [Source: (PushbackInputStream); line: 3, column: 13] (through reference chain: com.graphql.blog.model.Post["postedBy"])]

I was expecting postedBy column will store "402880ee73aa45570173aa462ea00001" as the user already exists and in response, it will send with user details automatically fetching user details for that post.

答案1

得分: 3

你之所以出现错误,是因为字符串字段无法反序列化为User对象。

我原本期望postedBy列将存储用户已存在的"402880ee73aa45570173aa462ea00001",并且在响应中会自动获取该用户的详细信息。

不,Spring无法自动完成这一操作。首先,需要通过JSON正确反序列化ID,就像这样:

{
    "title": "The Graphql way of design",
    "postedBy": {
        "id": "402880ee73aa45570173aa462ea00001"
    },
    "content": "The content of blog"
}

然后,首先按ID获取User并设置到Post中,例如:

Optional<User> user = userRepository.findById(post.getPostedBy.getId());
post.setUser(user.get());

还需要使用@JoinColumn来指定要在post表中存储用户外键的字段,如下所示:

@ManyToOne
@JoinColumn(name = "postedBy")
private User postedBy;
英文:

You are getting the error because a string field can not deserialize into object of User.

> I was expecting postedBy column will store
> "402880ee73aa45570173aa462ea00001" as the user already exists and in
> response, it will send with user details automatically fetching user
> details for that post.

No, spring can't do that automatically. To do it first properly deserialize the id by using json like this.

{
    &quot;title&quot;:&quot;The Graphql way of design&quot;,
    &quot;postedBy&quot;:{
                  &quot;id&quot;: &quot;402880ee73aa45570173aa462ea00001&quot;
               },
    &quot;content&quot;:&quot; The content of blog &quot;
}

Then fetch the User by id first and set in Post, Ex:

Optional&lt;User&gt; user = userRepository.findById(post.getPostedBy.getId());
post.setUser(user.get());

And use @JoinColumn for the field you want to store foreign key for user in post table.

@ManyToOne
@JoinColumn(name = &quot;postedBy&quot;)
private User postedBy;

答案2

得分: 1

根据您的要求,您应该放置以下代码:

在类User中:

@OneToMany(mappedBy = "postedBy", cascade = CascadeType.DETACH)
private List<Post> posts;

在类Post中:

@ManyToOne
@JsonIgnore
private User postedBy;
英文:

As per your requirement, you should put the following code:

In the class, User:

@OneToMany(mappedBy = &quot;postedBy&quot;, cascade = CascadeType.DETACH)
private List&lt;Post&gt; posts;

In the class, Post:

@ManyToOne
@JsonIgnore
private User postedBy;

答案3

得分: 1

@JsonIdentityInfo注解添加到User类中:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")

用于指示注解类型或属性的值应该被序列化,以便实例可以包含附加的对象标识符(除了实际的对象属性),或者作为一个引用,其中包含一个引用完整序列化的对象标识符。

英文:

Add the @JsonIdentityInfo annotation to the User class:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = &quot;id&quot;)

> Annotation used for indicating that values of annotated type or property should be serializing so that instances either contain additional object identifier (in addition actual object properties), or as a reference that consists of an object id that refers to a full serialization.

huangapple
  • 本文由 发表于 2020年8月1日 22:22:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/63206263.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定