James111
James111

Reputation: 15903

Hibernate allow foreign key to be one of many classes?

I'm trying to implement hashtag functionality in my database, allowing me to assign a hashtag to different classes. Is it possible to have the foreign key inside the tags class, be one of many different classes (Article, Video, Image)? This would mean having a discriminator column.

E.g

@Entity
@Table(name="tags")
public class Tags {
    private String tagName; // the hashtag name; E.g cool-photo
    private <Article, Video, Photo> relatedObject; 
    private String type; // Can either be Article, Video, Photo
}

In this example I'd be able to run a simple query:

select t.* from tags t where type = 'article' and tagName = 'tag-searching-for' 
INNER JOIN Article a ON t.relatedObject = a.articleId;

This would return a bunch of <type-requested> objects for the type requested (in this case, articles)!

Is there a built in way of doing this with Hibernate or will I have to build my own solution (which Im happy to do, I'd rather check to see if theres a concret one first).

Upvotes: 0

Views: 46

Answers (1)

Michele Mariotti
Michele Mariotti

Reputation: 7459

There are two ways, where you can just use a super entity - inheritance.

  1. create Taggable, a new super entity for Article, Video, ...

    @Entity
    public class Tag 
    {
        private String tagName; // the hashtag name; E.g cool-photo
    
        @ManyToMany
        @JoinTable(...)
        private Set<Taggable> relatedObjects = new LinkedHashSet<>(); 
    }
    
    @Entity
    @Inheritance(...)
    public abstract class Taggable
    {
        @ManyToMany(mappedBy = "relatedObjects")
        protected Set<Tag> tags = new LinkedHashSet<>();
    }
    
    @Entity
    public class Article extends Taggable 
    {
        ...
    }
    
  2. make Tag a super entity

    @Entity
    @Inheritance(...)
    public abstract class Tag 
    {
        protected String tagName; // the hashtag name; E.g cool-photo
    }
    
    @Entity
    public class ArticleTag extends Tag
    {
        @ManyToMany(mappedBy = "tags")
        private Set<Article> articles = new LinkedHashSet<>();
    }
    
    @Entity
    public class Article
    {
        @ManyToMany
        @JoinTable(...)
        private Set<ArticleTag> tags = new LinkedHashSet<>();
    }
    

In both cases the query you probably will use more often (conversely to the one you brought in example) is something like [JPQL style - not SQL!]:

select a 
from Article a
    join a.tags t
where t.tagName = 'tag-searching-for' 

to get all articles with that specific tagName.

IMHO the first one requires less refactoring and less boilerplate code, but, due to java single-class inheritance limitation, could cause some problem if/when you'll extend your model in the future.

As a side note, I don't see the meaning in using a single relatedObject, so I changed it to a Set<>

Upvotes: 1

Related Questions