0

I am using Spring Data JPA (with hibernate as the provider) for my project and wondering when do I need a bidirectional mapping between entities?

In my use case, I have a CategoryGroup entity having a @ManyToOne relationship to a Department entity. Currently, I don't have a corresponding @OneToMany relation in the Department entity. From what I could understand looking at other posts unless I need to delete via my entity/hibernate, I probably don't need to do it. I am wondering what else do I get by having a bidirectional relationship?

This is my Department excluding the accessors:

@Entity
  @Table(name="dbo.Department")
  public class Department 
  {
        @Id
        @Column(name="id")
        private long id;
            
        @Column(name="name")
        private String name;
  }

This is CategoryGroup excluding accessors:

@Entity
@Table(name="dbo.CategoryGroup")
public class CategoryGroup
{
    @Id
    @Column(name="id")
    private long id;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="dept_id")
    private Department department;
    
    @Column(name="name")
    private String name;
    
    public CategoryGroup()
    {       
    }
    
    public CategoryGroup(String name, Department department)
    {
        this.name = name;
        this.department = department;
    }
}

As a follow up, my structure is hierarchical in nature. Category entity has a @ManyToOne relationship to a CategoryGroup entity and further on SubCategory entity has a @ManyToOne relationship to a Category entity.

If I keep adding bidirectional relation mapping on the parent side of the relationship then would that mean that once I retrieve the Department I will end up getting the whole entity hierarchy right upto SubCategory? For my use case that won't be desirable. Will marking the relationship with FetchType.LAZY alleviate that?

Thanks

linuxNoob
  • 600
  • 2
  • 14
  • 30
  • Did you mean you are getting data recursively for bi-directional relation? – Eklavya Aug 18 '20 at 06:06
  • @User-Upvotedon'tsayThanks Actually, I was getting an error when I put @OneToMany annotation on the `Department`. @OneToMany(cascade = CascadeType.ALL, mappedBy="department", orphanRemoval=true) private List categoryGroups; – linuxNoob Aug 18 '20 at 18:46
  • Can you add the error in question ? – Eklavya Aug 18 '20 at 18:48
  • @User-Upvotedon'tsayThanks Request processing failed; nested exception is HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain:ArrayList[0]->com.CategoryGroup["department"]->com.Department_$$_jvstbb0_1["handler"]) – linuxNoob Aug 18 '20 at 20:26
  • @User-Upvotedon'tsayThanks not sure if I need to implement Serializable. Also, I am not overriding equals or hashcode in `CategoryGroup`. I was reading something about that too. – linuxNoob Aug 18 '20 at 20:27
  • Add @JsonIgnore on `categoryGroups` to ignore serialize it – Eklavya Aug 18 '20 at 20:28
  • @User-Upvotedon'tsayThanks still the same exception. I tried to follow the answer given here - https://stackoverflow.com/questions/52656517/no-serializer-found-for-class-org-hibernate-proxy-pojo-bytebuddy-bytebuddyinterc but that seems to add `handler` and `hibernateLazyInitializer` to the response (which I'm not sure why are they being added) as well as adds the `Department` to the response. I did newly add accessors for the `Department` in `CategoryGroup` though but I thought with lazy initialization it won't be fetched? – linuxNoob Aug 18 '20 at 20:40
  • Are you using hibernateLazyInitializer ? – Eklavya Aug 18 '20 at 20:40
  • @User-Upvotedon'tsayThanks unless it's being used by default, I'm not adding it. spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect and spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl are the only hibernate properties in my application.properties. – linuxNoob Aug 18 '20 at 20:42

1 Answers1

1

OneToMany and ManyToMany associations are lazy by default, so you will not fetch the whole hierarchy when you add these associations.

Generally, adding these associations can greatly help you with querying as it reduces the need for explicit entity joins based on the join condition. In addition to that, you can define delete cascading if you need that i.e. if a Department is deleted you might want to delete all CategoryGroups associated with it.

Apart from all that, it might be desireable to explicitly separate domains from a modelling point of view. You might want a Deparment to be isolated i.e. don't know anything about the objects that are connected to it.

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58
  • I do have `Department` as a separate entity currently, what else does isolating it entail? I am probably misunderstanding you but your last paragraph seems to be contradictory to the first two because in my case `Department` will be the `OneToMany` side so in that sense it will know about the objects that are connected to it. – linuxNoob Aug 18 '20 at 14:54
  • You were asking about bidirectional associations in general and I tried to give you reasons for doing it and avoiding it. In the end, it always depends on what you want to achieve. Although I consider adding these bidirectional assocations is in general a good this, adding the `Set` to `Department` might be undesirable because you introduce a model/code dependency. Depending on what you want/need, you can do one or the other. – Christian Beikov Aug 19 '20 at 09:56
  • Is it possible to have a bidirectional relationship without including a Collection of CategoryGroup in Department? For deletion will declaring @OnDelete(action = OnDeleteAction.CASCADE) on the `Department` instance in `CategoryGroup` help? On a tangential note, does it matter if it is a Set or a List? I suppose what I want to know is in which case will it be a good idea vs where it is undesirable? – linuxNoob Aug 19 '20 at 14:41
  • 1
    Like a wrote, in general I think it's a good idea. The only reason for not including it, is IMO when you want to isolate the model(e.g. `Department`). The `@OnDelete` will only remove table rows on the DBMS side without Hibernate knowing about it. This might be ok but could lead to issues. Maybe there are more cascading deletes that should happen? Maybe you have an entity listener that you want to be triggered pre-remove? – Christian Beikov Aug 20 '20 at 06:05