JPA polymorphic oneToMany

后端 未结 4 2097
栀梦
栀梦 2020-12-19 11:44

I couldn\'t figure out how to cleanly do a tag cloud with JPA where each db entity can have many tags.

E.g

Post can have 0 or more Tags User can have 0 or mo

相关标签:
4条回答
  • 2020-12-19 12:33

    If you don't need polymorphic queries such as "get everything tagged tagged Foo", then you can also introduce a new entity (say TaggingTarget), and create a unidirectional one-to-one relation from User (Post, etc) to TaggingTarget and many-to-many relation between TaggingTarget and Tag:

    @Entity
    public class User {
        @OneToOne
        private TaggingTarget target;
        ...
    }
    
    @Entity
    public class TaggingTarget {
        @ManyToMany(...)
        private Set<Tag> tags;
        ...
    }
    
    @Entity
    public class Tag {
        @ManyToMany(...)
        private Set<TagTarget> targets;
        ...
    }
    

    The difference from Affe's solution is that you don't need a tag.getTaggedUsers(), tag.getTaggedPosts(), etc and can add new tagged entities without changing Tag. Tagged entities can be queried using JPQL:

    select u from User u where :tag member of u.target.tags
    

    or

    select u from User u join u.target.tags t where t.name = :name 
    
    0 讨论(0)
  • 2020-12-19 12:39

    why dont you just map a Collection of Tags or even Strings?

    sudocode:

    @Entity
    @Table(name="entities")
    class MyEntity{
        long id;
        String someField;
        @ManyToMany(targetEntity=Tag.class)
        @JoinTable(name="entities_to_tags",
             joinColumns={
                 @JoinColumn(name="id",  
                 referencedColumnName="entity_id",
                 inverseJoinColumns={
                     @JoinColumn(name="id", referencedColumnName="tag_id")})
        List<Tag> tags;
        [...getter&setter...]
    }
    
    @Entity
    @Table(name="tags")
    class Tag{
        @Id
        @GeneratedValue
        long id;
        String title;
        [....getter & setter...]
    }
    
    0 讨论(0)
  • 2020-12-19 12:42

    This seems like ManyToMany, not one to Many. Users can have multiple tags, and a tag can be associated with more than one user?

    You would only need such a superclass if you want to be able to have a relationship on your Tag to a single collection that contains every object marked with that tag. Do you have a requirement for a tag.getOneGiantCollectionOfEveryTaggedEntity() method?

    Since the marked objects don't seem to otherwise have anything in common, does such a collection really have any value in your application domain? It could also ostensibly be quite large and not something you'd really want to work with via object relationships anyway. From a practical standpoint, without knowing about your use case, it seems like tag.getTaggedUsers(), tag.getTaggedPosts() etc are more useful.

    Sorry, guess I'm asking more questions than giving answers, but it's not clear what you want your finished object domain to look like :)

    edit:

    Maybe the actual answer then to the question asked is just "No, Hibernate will not map for you you a Raw Collection of types with no common ancestor that just happen to all have foreign keys to your entity." You don't neccessarily have to impose a 'fake' superclass on your entities, but if you don't then you'll have to make a join table.

    .?

    0 讨论(0)
  • 2020-12-19 12:47

    Is there a better way in JPA than having to make all the entities subclass something like Taggable abstract class?

    Let's forget the example :) JPA does support polymorphic associations but the target classes have to be part of an inheritance hierarchy. And here are some more rules of thumb about inheritance strategies:

    • SINGLE_TABLE:
      • All the classes in a hierarchy are mapped to a single table
      • This strategy provides good support polymorphic relationships between entities and queries that cover the entire class hierarchy.
      • May contain null fields for some subclass data
    • TABLE_PER_CLASS:
      • Each class in a hierarchy mapped to a separate table and hence, provides poor support for polymorphic relationships
      • requires SQL union or separate SQL queries for each subclass
    • JOINED
      • no null fields => compact data
      • This provides good support for polymorphic relationships, but requires one or more join operations – may result in poor performance

    In short, if your subclasses declare relatively few properties, prefer the SINGLE_TABLE strategy. If not, use a JOINED strategy unless you have a deep hierarchy (in which case the cost of joins may become more expensive than unions and then TABLE_PER_CLASS would be "less worse").

    References

    • JPA 1.0 Specification
      • Section 2.1.9 "Inheritance"
      • Section 2.1.10 "2.1.10 Inheritance Mapping Strategies"
    0 讨论(0)
提交回复
热议问题