Гибернация отношения OneToMany с неуникальным ключом

#hibernate #jpa #one-to-many

#гибернация #jpa #один ко многим

Вопрос:

Я не могу описать свою проблему, я повторяю ее с помощью примера:

У меня есть две сущности (таблицы): отдел и человек. Обе таблицы имеют код поля, который не является уникальным.

Как я могу определить множество двунаправленных связей между этими таблицами?

  1. У Departmen есть коллекция Persons, которая возвращает все объекты с Person.Отдел эквализации кода.код
  2. У партнера есть отделы сбора, которые возвращают все объекты с отделом.ПАРТНЕР CODE eq.код

Мне нужно определение отношения — нет запроса sql или hpql.

——— Оригинальный вопрос ——-

Мне нужно создать отношение гибернации один ко многим между отделом и человеком (в одном отделе много людей). Отдел и лица имеют срок действия (ValidFrom, validTill)

 class Department {
  Long id;
  String code; 
  String name;
  Date validFrom;
  Date validTill;
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "departmentId")
  @OnDelete(action = OnDeleteAction.CASCADE)
  private Set<Person> persons = new HashSet<Person>();
}
  

  class Person {
      Long id;
      String name;
      String surname;
      Date validFrom;
      Date validTill;
    }
  

Без ORM (hibernate) легко выбрать сотрудников определенного отдела на указанную дату:

 select P.* from Person P, Deparment d 
where d.code = ? and 
p.department_id = d.department_id and 
? between d.validFrom and d.validTill and 
? between p.validFrom and p.validTill
  

Отношение должно использовать неуникальный ключ (КОД) вместо идентификатора отдела.

Возможно ли сделать что-то подобное с hibernate?

Мне не нужны отдельные объекты и создавать запросы самостоятельно.

Я хочу использовать все функции, которые предлагает ORM (отложенная загрузка, сохранение хранилища …)

Комментарии:

1. Вы хотите получить только данные или при вставке нового отдела с тем же кодом, что и у существующего, обновить все отношения?

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

Ответ №1:

ОБНОВЛЕНО

Во-первых, вы упоминаете, что хотите использовать все функции, которые предлагает ORM. Если это так, то вам нужно использовать схему, к которой подходит Hibernate. Существуют аннотации, доступные как в JPA persistence API, так и в API, специфичном для гибернации, которые позволяют вам легче работать с «устаревшими» базами данных. Но если вы хотите полного и правильного использования гибернации, вам необходимо разработать свою схему в соответствии с тем, что ожидает гибернация.

Вы можете сделать то, что вы просите в этом случае, используя формулу соединения вместо столбца соединения для ваших отношений. Формула соединения является допустимым фрагментом SQL (что может снизить переносимость). Я оставил фактический SQL в примере ниже.

 public class Person {
    ...
    @OneToMany
    @JoinFormula("sql fragment")
    private List<Department> departments;
    ...
}

public class Department {
    ...
    @OneToMany
    @JoinFormula("sql fragment")
    private List<Person> people;
    ...
}
  

Вам также следует рассмотреть возможность обработки кода как объекта гибернации:

 @Embeddable
public class Code {
    ...
    @Column(nullable = false, length = 20)
    private String code;
    ...
}
  

Вместо простой строки, чтобы использование кода в связях сущностей более эффективно управлялось контекстом сохранения гибернации и процессом сопоставления строк.

Наконец, рассмотрите возможность фактического отображения отношений между Person и Department в виде таблицы соединений в вашей схеме. Тогда вы сможете воспользоваться @ManyToMany @JoinTable аннотациями и для создания реальных отношений на основе схемы в ваших сущностях.

Комментарии:

1. Прошу прощения. Я не понимаю. Отношение OneToMany и ManyToOne использует первичный и внешний ключ. Но мне это не нужно. Моя проблема в том, что мне нужно отношение без PK-FK.

2. Я обновил свой ответ, чтобы показать использование отношений гибернации без «реальных» внешних ключей.

3. Спасибо. Хорошее объяснение. Не могли бы вы предоставить фрагмент sql для объединения двух таблиц с помощью КОДА?

4. Может быть, вы можете порекомендовать лучший способ. Мне это нужно для поддержки планирования данных. Например. Пользователь может подготовить несколько записей, которые будут действительны с заданным интервалом (ValidFrom, validTill). Одновременно может быть только одна допустимая запись, интервал не обязательно должен быть непрерывным. Пример: у меня есть отдел AAA, который действителен с 1.1.2010 по 31.12.2099. Где-нибудь в будущем я хочу переименовать отдел, я изменяю действительность существующей записи на 31.12.2012 и создаю новую с новым именем, действительную с 1.1.2013 по 31.12.2099. чтобы иметь возможность поддерживать назначение person, я также должен добавить валидность в таблицу join

Ответ №2:

Вы можете определить фильтр. Это позволяет вам добавлять эту проверку к каждому выполняемому вами запросу или отключать ее, если хотите.

Пример:

 <class name="Department" ...>
    ...
    <many-to-one name="person" column="person_id" class="Person"/>
    <property name="validFrom" type="date" column="validFrom"/>
    <property name="validTill" type="date" column="validTill"/>
    <property name="code" type="string" column="code"/>
    ...
    <!--
        Note that this assumes non-terminal records have an eff_end_dt set to
        a max db date for simplicity-sake
    -->
    <filter name="effectiveDate"
            condition="code = :code and :asOfDate BETWEEN validFrom and validTill"/>
</class>
  

С уважением.

Комментарии:

1. Фильтр не работает нормально: (Потому что с этой аннотацией связана связь между первичным ключом (отделом) и внешним ключом (person — DepartmentID). Но мне нужна ссылка на человека, не являющаяся уникальным «кодом» отдела

2. Это был всего лишь пример, но он вписывается в описание вашей проблемы. Вы можете поместить что угодно в фильтр (sql с именованными параметрами)

3. … или можно использовать HQL или динамически добавлять критерии.

4. Пожалуйста, можете ли вы предоставить аннотацию для связи между отделом и человеком, где Persons ссылается на неуникальные ключи в отделе? Я могу вам ManyToMany, но когда я добавляю нового пользователя, я хотел бы связать его со всеми отделами (с тем же кодом) без создания записей для объединения в таблицу.

5. Я могу использовать ManyToMany, но это не совсем то, что мне нужно. Если я добавлю человека в отдел DEP1, я должен связать его вручную со всеми отделами с кодом DEP1. Если я когда-нибудь в будущем добавлю новый отдел с кодом DEP1, мне придется связать новый отдел со всеми лицами, принадлежащими DEP1. Потому что он использует таблицу соединений, которая ссылается на PK обеих таблиц. Есть ли способ установить отношение, которое напрямую использует department.code?