Home > Back-end >  Why we need repeat ManyToOne annotation if the other is OneToMany in JPA?
Why we need repeat ManyToOne annotation if the other is OneToMany in JPA?

Time:12-07

I wanna understand why JPA needs double annotation in Mapping, OneToMany in the dominant class and ManyToOne in the weaker class, if Event is ManyToOne, Category is OneToMany.

@Entity
@Table(name = "event")
public class Event {

    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;

    public Category getCategory() {
        return category;
    }
}
@Entity
@Table(name = "category")
public class Category {

    @OneToMany
    @JoinColumn(name = "category_id")
    private List<Event> events;

    public List<Event> getEvents() {
        return events;
    }
}

CodePudding user response:

JPA does not need any double mapping. It actually needs only @ManyToOne relationship. Why? If you think the database side, in a such relationship what you call weaker class, the way to implement that relationship is usually to add column like (pseudo information, in your case):

category_id BIGINT REFERENCES category(id)

JPA knows that because of annotation @ManyToOne and (implementation) is able to generate foreign keys etc.

However @OneToMany is not required. It does not normally affect to datatabase in any way than selecting stuff when needed. It is just to populate the list in Java side and to fetch all weaker rows that have the same stronger_id as the stronger class has. One could say that it is a convenience way to populate list of weaker without any extra queries.

More to read

CodePudding user response:

Adding to what @Pirho stated. JPA does not require duplicate mappings - in fact, some JPA providers will flag your posted code and throw warnings and exceptions outlining that it is a problem. You have setup Category and Event to both have a JoinColumn definition, so both mappings control the Event.category_id column. This should not be allowed because you get into situations where a specific Event instance can reference CategoryA, but be in CategoryB's event list. What happens in the database is then undefined, as there is only one Event.category_id foreign key. There is no concept of a dominant mapping type or class.

What might have been meant is something more like:

public class Event {
    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;
}

public class Category {
    @OneToMany(mappedBy="category")
    private List<Event> events;
}

This is known as a bidirectional relationship, as you can traverse it from both sides in the object model. In the database though, there is only the Event.category_id, and it is controlled/owned by the Event.category reference/relationship. If you set Event.category to a different Category instance, JPA will update the foriegn key - it is up to you to set the Category instances appropriately so that the instances in memory are insynch with the database. Otherwise, they might be stale until they get reloaded. category, use it in queries, and even merge/persist/delete

There is no need for this though. You could map it as a unidirectional relationship from either side:

public class Event {
    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;
}

Or from the other side if the Event.category relationship doesn't exist:

public class Category {
    @OneToMany
    @JoinColumn(name = "category_id")
    private List<Event> events;
}

There are a few questions touching on this already

  • Related