Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Many-To-One with join Table in hibernate resource classes for a JAX-RS using Jersey

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;
}

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.

like image 308
Ali Avatar asked Jul 07 '12 22:07

Ali


1 Answers

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
like image 174
JB Nizet Avatar answered Oct 19 '22 14:10

JB Nizet