Связи в таблицах. ORM

363
11 февраля 2017, 06:52

Довольно детский вопрос, но я запутался. Использую Hibernate. Он же и создает таблицы. Есть сущность пользователь, есть сущность сессия. У одного пользователя может быть много сессий.

public class Session {
    @Id
    @Column(name = "id")
    @GeneratedValue()
    private long id;
    @Column(name = "token")
    private String token;
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}
public class User {
    @Id
    @Column(name = "id")
    @GeneratedValue
    private long id;
    @Column(name = "name", nullable = false)
    private String name;
    @OneToMany(fetch = FetchType.LAZY)
    private List<Session> sessions;
}

Собственно что не так. Я хочу чтобы была сгенерирована такая структура в БД:

Users(id, name)
Sessions(id, token, userId)

В целом то оно так и вышло. И даже заполняется правильно. Но дополнительно генерируется ещё одна таблица, которая остается пустой. При тестовом созаднии и входе пользователя:

Таблица Users

Таблица Sessions

Таблица UserSessions

Может мне кто нибудь разжует, что к чему? Я в принципе понимаю, зачем вообще создавать такую таблицу. У одного пользователя может быть (на самом деле нет, но гибернейт же этого не знает) теоретически несколько сессий, и в то же время одна сессия может быть у нескольких пользователей, аля экономия места + целостность БД. Но почему она тогда не заполняется?

Чтобы разобраться интересны оба случая, как заставить её (таблицу UserSessions) заполняться и убрать этот userId из таблицы Sessions; так и наоборот, как убрать таблицу UserSessions, оставив userId. И как так получилось у меня что создается не используемая таблица?

Answer 1

Всё просто. Таким образом у Вас получились две независимые друг от друга односторонних связи.

Одна-ко-многим (user->sessions) совершенно естественно создаёт join-таблицу.

Чтобы создать обратную сторону двусторонней связи следует делать так:

public class User {
    ...
    @OneToMany(mappedBy = "user")
    private List<Session> sessions;
    ....
}

Так JPA видит, что эта связь - это обратная сторона двусторонней связи. А прямая задана в Session атрибутом user.

При этом никаких лишних join-таблиц не будет, ибо теперь известно, что связь держится через session.

Answer 2

Разобрался. Нужно было залезть в документацию (на всяких обучающих сайтах толкового мало). Вопрос удалять не буду, вдруг пригодится кому нибудь.

В общем есть три ситуации.

  • Описано ManyToOne. Тогда создаётся только внешний ключ. Никаких таблиц дополнительных не создается.

  • Описано OneToMany. Делается через дополнительную таблицу.

  • Описано OneToMany и ManyToOne. При этом снова работает только через внешний ключ. Но! У OneToMany обязательно должно быть прописано MapedBy, иначе сработает случай выше и будет создана дополнительная таблица.

Всё же вопрос, интересен... А почему так? Чем так принципиально отличается OneToMany от ManyToOne, что без таблицы никак? На который я сам логически и нашел ответ ) Опять же, может кому то полезно будет. При ManyToOne мы в таблице где может быть "много" объектов описываем свойство ссылающиеся на "один" объект. Никакой дополнительной таблицы не нужно. Но если мы описываем OneToMany, то получается в объекте "один" должен быть список других объектов. А этот список и выражается в этой самой дополнительной таблице. Вот так.

READ ALSO
Java Вопрос по файлам и чтению их в массивы

Java Вопрос по файлам и чтению их в массивы

Простите, если путанно и многословно объясняю

299
Не округлять double до целого числа [дубликат]

Не округлять double до целого числа [дубликат]

На данный вопрос уже ответили:

339
/utils/add/message - не могу сделать RegExp

/utils/add/message - не могу сделать RegExp

Подскажите пожалуйста как составить regexp для такой строки /utils/add/message? таких /действие может быть сколько угодно

257
Проверка существования ключа в Map

Проверка существования ключа в Map

Необходимо в HashMap сохранить "ключ -> массив значений"

356