JPA полиморфная oneToMany - PullRequest
       26

JPA полиморфная oneToMany

5 голосов
/ 26 мая 2010

Я не мог понять, как правильно создать облако тегов с JPA, где каждая сущность БД может иметь много тегов.

* 1003 например *

Сообщение может иметь 0 или более тегов Пользователь может иметь 0 или более тегов

Есть ли лучший способ в JPA, чем сделать все сущности подклассами чем-то вроде абстрактного класса Taggable? Где объект Tag будет ссылаться на множество Taggables.

Редактировать: облако тегов - это всего лишь пример, который упрощает мою проблему. В моем сценарии отношение должно быть OneToMany, где тег нельзя использовать повторно.

спасибо

Ответы [ 4 ]

1 голос
/ 27 мая 2010

Есть ли лучший способ в JPA, чем сделать все подклассы сущностей чем-то вроде абстрактного класса Taggable?

Давайте забудем пример :) JPA поддерживает полиморфные ассоциации, но целевые классы должны быть частью иерархии наследования. И вот еще несколько практических правил о стратегиях наследования:

  • SINGLE_TABLE:
    • Все классы в иерархии отображаются в одну таблицу
    • Эта стратегия обеспечивает хорошую поддержку полиморфных связей между сущности и запросы, которые охватывают вся иерархия классов.
    • Может содержать пустые поля для некоторых данных подкласса
  • TABLE_PER_CLASS:
    • Каждый класс в иерархии сопоставляется с отдельной таблицей и, следовательно, обеспечивает плохая поддержка полиморфных отношения
    • требует объединения SQL или отдельных запросов SQL для каждого подкласса
  • JOINED
    • нет пустых полей => компактные данные
    • Это обеспечивает хорошую поддержку полиморфных отношений, но требуется одна или несколько операций соединения - может привести к снижению производительности

Короче говоря, если ваши подклассы объявляют относительно немного свойств, предпочтите стратегию SINGLE_TABLE. Если нет, используйте стратегию JOINED, если у вас нет глубокой иерархии (в этом случае стоимость объединений может стать дороже, чем союзов, и тогда TABLE_PER_CLASS будет «менее опасным»).

Ссылки

  • JPA 1.0 Технические характеристики
    • Раздел 2.1.9 «Наследование»
    • Раздел 2.1.10 «2.1.10 Стратегии отображения наследования»
1 голос
/ 26 мая 2010

Это похоже на ManyToMany, а не один на Многих.У пользователей может быть несколько тегов, и тег может быть связан с несколькими пользователями?

Такой суперкласс вам понадобится только в том случае, если вы хотите иметь возможность связать свой тег с одной коллекцией, содержащейкаждый объект помечен этим тегом.У вас есть требование для метода tag.getOneGiantCollectionOfEveryTaggedEntity()?

Поскольку у отмеченных объектов, кажется, нет ничего общего, действительно ли такая коллекция имеет какое-либо значение в вашей области приложения?Якобы он также может быть довольно большим, и в любом случае вы не захотите работать с ним через отношения объектов.С практической точки зрения, не зная о вашем сценарии использования, кажется, что tag.getTaggedUsers(), tag.getTaggedPosts() и т. Д. Более полезны.

Извините, думаю, я задаю больше вопросов, чем даю ответы, но это не яснокак вы хотите, чтобы ваш готовый объектный домен выглядел следующим образом:)

edit:

Возможно, тогда фактическим ответом на заданный вопрос будет просто «Нет, Hibernate не будет отображать для вас коллекцию Rawу типов без общего предка, которые просто случаются со всеми, есть внешние ключи к вашей сущности. "Вам необязательно навязывать «поддельные» суперклассы вашим сущностям, но если вы этого не сделаете, вам придется создать объединяющую таблицу.

.?

0 голосов
/ 26 мая 2010

Если вам не нужны полиморфные запросы, такие как «получить все, помеченные тегами, как Foo», тогда вы также можете ввести новый объект (скажем, TaggingTarget) и создать однонаправленное отношение «один к одному» из User (Post и т. Д.) До TaggingTarget и отношение «многие ко многим» между TaggingTarget и 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;
    ...
}

Отличие от решения Affe заключается в том, что вам не нужны tag.getTaggedUsers(), tag.getTaggedPosts() и т. Д., И вы можете добавлять новые тегированные объекты без изменения Tag. Помеченные объекты могут быть запрошены с использованием JPQL:

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

или

select u from User u join u.target.tags t where t.name = :name 
0 голосов
/ 26 мая 2010

почему вы не наносите на карту коллекцию тегов или даже строк?

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...]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...