使用 Jersey 的 JAX-RS 的休眠资源类中的多对一连接表类中、资源、Jersey、JAX

2023-09-07 08:51:32 作者:倘若初见

I am implementing a RESTful Web Service using Jersey. I use hibernate to communicate with the database (mySQL). My hibernate resource classes includes:

@Entity
public class Activity {

    @Id
    @GeneratedValue
    private long id;

@ManyToOne
    @JoinTable(name="category_activity",
    joinColumns={@JoinColumn(name="activities_id")},
    inverseJoinColumns={@JoinColumn(name="Category_id")})
    private Category category;
}

and the Category class:

@Entity
public class Category {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany
    @Fetch(FetchMode.JOIN)
    @JoinTable(name = "category_activity",
    joinColumns = { @JoinColumn(name = "Category_id") }, 
    inverseJoinColumns = { @JoinColumn(name = "activities_id") })
    @JsonIgnore
    private Collection<Activity> activities;
}
整合JAX RS之利用Jersey框架实现RESTful

I used this query to fetch the ativities:

session.createQuery("from Activity a join a.category cs where cs.id= :categoryId order by a.key").setLong("categoryId", categoryId).list();

The result in JSON format is not right like:

[[{"id":26,"key":"other","name":"Other","cost":100.0,"category":{"id":10,"name":"General","description":""}},{"id":10,"name":"General","description":""}]]

As you see category is printed 2 times and we have a extra [] around it. When I use another mechanism of One-To-Many relation in Category class like:

@OneToMany(targetEntity = Activity.class, mappedBy = "category", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JsonIgnore
private Collection<Project> activities;

And in Activity class:

@ManyToOne(optional = false)
    private Category category;

And this query:

session.createQuery("from Activity as a where a.category.id= :categoryId order by a.key").setLong("categoryId", categoryId).list();

Everything works fine. But I have to use join table because I do not suppose to change the database.

The proper result should look like:

[{"id":26,"key":"other","name":"Other","cost":100.0,"category":{"id":10,"name":"General","description":""}}]

I appreciate for any help.

解决方案

Define the join table on the many side, but don't define it once again on the one side. This creates two unidirectional associations mapped with the same table instead of one bidirectional association.

A bidirectional association always has an owner side (where you specify the join column or join table to use, and an inverse side which says hat it's the inverse of the other side by using the mappedBy attribute:

public class Activity {

    @ManyToOne // owner side: it doesn't have mappedBy, and can decide how the association is mapped: with a join table
    @JoinTable(name="category_activity",
               joinColumns={@JoinColumn(name="activities_id")},
               inverseJoinColumns={@JoinColumn(name="Category_id")})
    private Category category;
}

public class Category {
    @OneToMany(mappedBy = "category") // inverse side: it has a mappedBy attribute, and can't decide how the association is mapped, since the other side already decided it.
    @Fetch(FetchMode.JOIN)
    @JsonIgnore
    private Collection<Activity> activities;
}

EDIT:

Also, your query should only select the activity, and not all the entities joined by the query, by adding a select clause:

select a from Activity as a where a.category.id= :categoryId order by a.key