简体   繁体   中英

Mapping one-to-many with no duplicates

I'm attempting to do what I believe is a 'one-to-many' relationship in Jpa Spring JPA (Hibernate) where by I have three tables (Post, Tag, Post_tag).

One post may have many tags, and multiple posts may share the same tag as well as other tags. Where tags overlap, there should only be one instance of that tag in the tag table.

The structure goes a little like the following:

Post:

  • id
  • name

Post_tag:

  • post_id
  • tag_id

Tag:

  • id
  • tag

My understanding is that this is a 'many-to-one' relation from the Post's perspective, and a 'one-to-many' from the Tags perspective. Currently I've managed to make this work using a Many-To-One relationship, however this is producing many identical tags with different IDs and cluttering the database slowing it down and making me result in caching results in redis an attempt to speed up queries which is a temporary fix!

What I currently have is:

@Table(name="Post")
public class Post implements Serializable {

...

@ManyToOne(targetEntity = Tags.class, cascade = {CascadeType.ALL, CascadeType.MERGE})
@JoinTable(name = "post_tags",
            joinColumns = {@JoinColumn(name = "post_id")},
            inverseJoinColumns = {@JoinColumn(name = "tag_id", unique=true)})
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="post_tags")
    public Set<Tags> tags;

And the tags table:

@Column(name = "tag", unique = true)
private String tag;

Thanks!

Your scnerio is actually a many to many relationship. You better use @ManyToMany . Something like below.

@Entity
@Table(name = "Tag")

public class Tag{ 
    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(
        name = "Post_Tag", 
        joinColumns = { @JoinColumn(name = "tag_id") }, 
        inverseJoinColumns = { @JoinColumn(name = "post_id") }
    )
    Set<Post> posts = new HashSet<>();

    // standard constructor/getters/setters
}

@Entity
@Table(name = "Post")
public class Post{    


    @ManyToMany(mappedBy = "posts")

    private Set<Tag> tags= new HashSet<>();

    // standard constructors/getters/setters   
}

Problem is your Post is referencing your Tag table. Should be your post reference your Post_Tag table to get the tag:

@Entity
@Table(name = "post")
public class Post implements Serializable {

  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Basic(optional = false)
  @Column(name = "id")
  private Integer id;
  @Column(name = "post")
  private String post;
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "postId")
  private List<PostTag> postTagList;
}

@Entity
@Table(name = "tag")
public class Tag implements Serializable {

  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Basic(optional = false)
  @Column(name = "id")
  private Integer id;
  @Column(name = "tag")
  private String tag;
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "tagId")
  private List<PostTag> postTagList;
}


@Entity
@Table(name = "post_tag")
public class PostTag implements Serializable {

  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Basic(optional = false)
  @Column(name = "id")
  private Integer id;
  @JoinColumn(name = "post_id", referencedColumnName = "id")
  @ManyToOne(optional = false)
  private Post postId;
  @JoinColumn(name = "tag_id", referencedColumnName = "id")
  @ManyToOne(optional = false)
  private Tag tagId;
}

The above has individual post and tag entities along with the PostTag entity which references both.

Now you can call post.getPostTagList() in a for loop to get all the tags to for the post for instance:

for (PostTag postTag : post.getPostTagList()) {
  Tag tag = postTag.getTag();
  String tagValue = tag.getTag();
}

One thing to note, hibernate by default lazy fetches so the list might get an error. You will have to write the query to do an eager fetch from your repository or however you fetch your data

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM